Ceph存储系统的逻辑层次结构以下图所示:web
自下向上,能够将Ceph系统分为四个层次:算法
(1)基础存储系统RADOS(Reliable, Autonomic, Distributed Object Store,便可靠的、自动化的、分布式的对象存储)编程
顾名思义,这一层自己就是一个完整的对象存储系统,全部存储在Ceph系统中的用户数据事实上最终都是由这一层来存储的。而Ceph的高可靠、高可扩展、高性能、高自动化等等特性本质上也是由这一层所提供的。所以,理解RADOS是理解Ceph的基础与关键。安全
物理上,RADOS由大量的存储设备节点组层,每一个节点拥有本身的硬件资源(CPU、内存、硬盘、网络),并运行着操做系统和文件系统。4.二、4.3节将对RADOS进行展开介绍。服务器
(2)基础库librados网络
这一层的功能是对RADOS进行抽象和封装,并向上层提供API,以便直接基于RADOS(而不是整个Ceph)进行应用开发。特别要注意的是,RADOS是一个对象存储系统,所以,librados实现的API也只是针对对象存储功能的。数据结构
RADOS采用C++开发,所提供的原生librados API包括C和C++两种,其文档参见[2]。物理上,librados和基于其上开发的应用位于同一台机器,于是也被称为本地API。应用调用本机上的librados API,再由后者经过socket与RADOS集群中的节点通讯并完成各类操做。架构
(3)高层应用接口dom
这一层包括了三个部分:RADOS GW(RADOS Gateway)、 RBD(Reliable Block Device)和Ceph FS(Ceph File System),其做用是在librados库的基础上提供抽象层次更高、更便于应用或客户端使用的上层接口。异步
其中,RADOS GW是一个提供与Amazon S3和Swift兼容的RESTful API的gateway,以供相应的对象存储应用开发使用。RADOS GW提供的API抽象层次更高,但功能则不如librados强大。所以,开发者应针对本身的需求选择使用。
RBD则提供了一个标准的块设备接口,经常使用于在虚拟化的场景下为虚拟机建立volume。目前,Red Hat已经将RBD驱动集成在KVM/QEMU中,以提升虚拟机访问性能。
Ceph FS是一个POSIX兼容的分布式文件系统。因为还处在开发状态,于是Ceph官网并不推荐将其用于生产环境中。
(4)应用层
这一层就是不一样场景下对于Ceph各个应用接口的各类应用方式,例如基于librados直接开发的对象存储应用,基于RADOS GW开发的对象存储应用,基于RBD实现的云硬盘等等。
在上文的介绍中,有一个地方可能容易引发困惑:RADOS自身既然已是一个对象存储系统,而且也能够提供librados API,为什么还要再单独开发一个RADOS GW?
理解这个问题,事实上有助于理解RADOS的本质,所以有必要在此加以分析。粗看起来,librados和RADOS GW的区别在于,librados提供的是本地API,而RADOS GW提供的则是RESTful API,两者的编程模型和实际性能不一样。而更进一步说,则和这两个不一样抽象层次的目标应用场景差别有关。换言之,虽然RADOS和S三、Swift同属分布式对象存储系统,但RADOS提供的功能更为基础、也更为丰富。这一点能够经过对比看出。
因为Swift和S3支持的API功能近似,这里以Swift举例说明。Swift提供的API功能主要包括:
因而可知,Swift(以及S3)提供的API所操做的“对象”只有三个:用户帐户、用户存储数据对象的容器、数据对象。而且,全部的操做均不涉及存储系统 的底层硬件或系统信息。不难看出,这样的API设计彻底是针对对象存储应用开发者和对象存储应用用户的,而且假定其开发者和用户关心的内容更偏重于帐户和数据的管理,而对底层存储系统细节不感兴趣,更不关心效率、性能等方面的深刻优化。
而librados API的设计思想则与此彻底不一样。一方面,librados中没有帐户、容器这样的高层概念;另外一方面,librados API向开发者开放了大量的RADOS状态信息与配置参数,容许开发者对RADOS系统以及其中存储的对象的状态进行观察,并强有力地对系统存储策略进行控制。换言之,经过调用librados API,应用不只可以实现对数据对象的操做,还可以实现对RADOS系统的管理和配置。这对于S3和Swift的RESTful API设计是不可想像的,也是没有必要的。
基于上述分析对比,不难看出,librados事实上更适合对于系统有着深入理解,同时对于功能定制扩展和性能深度优化有着强烈需求的高级用户。基于librados的开发可能更适合于在私有Ceph系统上开发专用应用,或者为基于Ceph的公有存储系统开发后台数据管理、处理应用。而RADOS GW则更适合于常见的基于web的对象存储应用开发,例如公有云上的对象存储服务。
RADOS的系统逻辑结构以下图所示
在使用RADOS系统时,大量的客户端程序经过与OSD或者monitor的交互获取cluster map,而后直接在本地进行计算,得出对象的存储位置后,便直接与对应的OSD通讯,完成数据的各类操做。可见,在此过程当中,只要保证cluster map不频繁更新,则客户端显然能够不依赖于任何元数据服务器,不进行任何查表操做,便完成数据访问流程。在RADOS的运行过程当中,cluster map的更新彻底取决于系统的状态变化,而致使这一变化的常见事件只有两种:OSD出现故障,或者RADOS规模扩大。而正常应用场景下,这两种事件发生 的频率显然远远低于客户端对数据进行访问的频率。
根据定义,OSD能够被抽象为两个组成部分,即系统部分和守护进程(OSD deamon)部分。
OSD的系统部分本质上就是一台安装了操做系统和文件系统的计算机,其硬件部分至少包括一个单核的处理器、必定数量的内存、一块硬盘以及一张网卡。
因为这么小规模的x86架构服务器并不实用(事实上也见不到),于是实际应用中一般将多个OSD集中部署在一台更大规模的服务器上。在选择系统配置时,应当 可以保证每一个OSD占用必定的计算能力、必定量的内存和一块硬盘。同时,应当保证该服务器具有足够的网络带宽。具体的硬件配置选择能够参考。
在 上述系统平台上,每一个OSD拥有一个本身的OSD deamon。这个deamon负责完成OSD的全部逻辑功能,包括与monitor和其余OSD(事实上是其余OSD的deamon)通讯以维护更新系 统状态,与其余OSD共同完成数据的存储和维护,与client通讯完成各类数据对象操做等等。
Ceph系统的逻辑结构就介绍到这里。下篇文章将着重说明Ceph(主要是RADOS)的工做原理和操做流程。
如图所示,RADOS集群主要由两种节点组成。一种是为数众多的、负责完成数据存储和维护功能的OSD(Object Storage Device),另外一种则是若干个负责完成系统状态检测和维护的monitor。OSD和monitor之间相互传输节点状态信息,共同得出系统的整体工 做状态,并造成一个全局系统状态记录数据结构,即所谓的cluster map。这个数据结构与RADOS提供的特定算法相配合,便实现了Ceph“无需查表,算算就好”的核心机制以及若干优秀特性。
本节将对Ceph的工做原理和若干关键工做流程进行扼要介绍。如前所述,因为Ceph的功能实现本质上依托于RADOS,于是,此处的介绍事实上也是针对RADOS进行。对于上层的部分,特别是RADOS GW和RBD,因为现有的文档中(包括Sage的论文中)并未详细介绍,还请读者多多包涵。
首先介绍RADOS中最为核心的、基于计算的对象寻址机制,而后说明对象存取的工做流程,以后介绍RADOS集群维护的工做过程,最后结合Ceph的结构和原理对其技术优点加以回顾和剖析。
Ceph系统中的寻址流程以下图所示:
上图左侧的几个概念说明以下:
1. File —— 此处的file就是用户须要存储或者访问的文件。对于一个基于Ceph开发的对象存储应用而言,这个file也就对应于应用中的“对象”,也就是用户直接操做的“对象”。
2. Ojbect —— 此处的object是RADOS所看到的“对象”。Object与上面提到的file的区别是,object的最大size由RADOS限定(一般为2MB或4MB),以便实现底层存储的组织管理。所以,当上层应用向RADOS存入size很大的file时,须要将file切分红统一大小的一系列object(最后一个的大小能够不一样)进行存储。为避免混淆,在本文中将尽可能避免使用中文的“对象”这一名词,而直接使用file或object进行说明。
3. PG(Placement Group)—— 顾名思义,PG的用途是对object的存储进行组织和位置映射。具体而言,一个PG负责组织若干个object(能够为数千个甚至更多),但一个object只能被映射到一个PG中,即,PG和object之间是“一对多”映射关系。同时,一个PG会被映射到n个OSD上,而每一个OSD上都会承载大量的PG,即,PG和OSD之间是“多对多”映射关系。在实践当中,n至少为2,若是用于生产环境,则至少为3。一个OSD上的PG则可达到数百个。事实上,PG数量的设置牵扯到数据分布的均匀性问题。关于这一点,下文还将有所展开。
4. OSD —— 即object storage device,前文已经详细介绍,此处再也不展开。惟一须要说明的是,OSD的数量事实上也关系到系统的数据分布均匀性,所以其数量不该太少。在实践当中,至少也应该是数十上百个的量级才有助于Ceph系统的设计发挥其应有的优点。
5. Failure domain —— 这个概念在论文中并无进行定义,好在对分布式存储系统有必定概念的读者应该可以了解其大意。
基于上述定义,即可以对寻址流程进行解释了。具体而言, Ceph中的寻址至少要经历如下三次映射:
1. File -> object映射
此次映射的目的是,将用户要操做的file,映射为RADOS可以处理的object。其映射十分简单,本质上就是按照object的最大size对file进行切分,至关于RAID中的条带化过程。这种切分的好处有二:一是让大小不限的file变成最大size一致、能够被RADOS高效管理的object;二是让对单一file实施的串行处理变为对多个object实施的并行化处理。
每个切分后产生的object将得到惟一的oid,即object id。其产生方式也是线性映射,极其简单。图中,ino是待操做file的元数据,能够简单理解为该file的惟一id。ono则是由该file切分产生的某个object的序号。而oid就是将这个序号简单连缀在该file id以后获得的。举例而言,若是一个id为filename的file被切分红了三个object,则其object序号依次为0、1和2,而最终获得的oid就依次为filename0、filename1和filename2。
这里隐含的问题是,ino的惟一性必须获得保证,不然后续映射没法正确进行。
2. Object -> PG映射
在file被映射为一个或多个object以后,就须要将每一个object独立地映射到一个PG中去。这个映射过程也很简单,如图中所示,其计算公式是:
hash(oid) & mask -> pgid
因而可知,其计算由两步组成。首先是使用Ceph系统指定的一个静态哈希函数计算oid的哈希值,将oid映射成为一个近似均匀分布的伪随机值。而后,将这个伪随机值和mask按位相与,获得最终的PG序号(pgid)。根据RADOS的设计,给定PG的总数为m(m应该为2的整数幂),则mask的值为m-1。所以,哈希值计算和按位与操做的总体结果事实上是从全部m个PG中近似均匀地随机选择一个。基于这一机制,当有大量object和大量PG时,RADOS可以保证object和PG之间的近似均匀映射。又由于object是由file切分而来,大部分object的size相同,于是,这一映射最终保证了,各个PG中存储的object的总数据量近似均匀。
从介绍不难看出,这里反复强调了“大量”。只有当object和PG的数量较多时,这种伪随机关系的近似均匀性才能成立,Ceph的数据存储均匀性才有保证。为保证“大量”的成立,一方面,object的最大size应该被合理配置,以使得一样数量的file可以被切分红更多的object;另外一方面,Ceph也推荐PG总数应该为OSD总数的数百倍,以保证有足够数量的PG可供映射。
3. PG -> OSD映射
第三次映射就是将做为object的逻辑组织单元的PG映射到数据的实际存储单元OSD。如图所示,RADOS采用一个名为CRUSH的算法,将pgid代入其中,而后获得一组共n个OSD。这n个OSD即共同负责存储和维护一个PG中的全部object。前已述及,n的数值能够根据实际应用中对于可靠性的需求而配置,在生产环境下一般为3。具体到每一个OSD,则由其上运行的OSD deamon负责执行映射到本地的object在本地文件系统中的存储、访问、元数据维护等操做。
和“object -> PG”映射中采用的哈希算法不一样,这个CRUSH算法的结果不是绝对不变的,而是受到其余因素的影响。其影响因素主要有二:
一是当前系统状态,也就是上文逻辑结构中曾经说起的cluster map。当系统中的OSD状态、数量发生变化时,cluster map可能发生变化,而这种变化将会影响到PG与OSD之间的映射。
二是存储策略配置。这里的策略主要与安全相关。利用策略配置,系统管理员能够指定承载同一个PG的3个OSD分别位于数据中心的不一样服务器乃至机架上,从而进一步改善存储的可靠性。
所以,只有在系统状态(cluster map)和存储策略都不发生变化的时候,PG和OSD之间的映射关系才是固定不变的。在实际使用当中,策略一经配置一般不会改变。而系统状态的改变或者是因为设备损坏,或者是由于存储集群规模扩大。好在Ceph自己提供了对于这种变化的自动化支持,于是,即使PG与OSD之间的映射关系发生了变化,也并不会对应用形成困扰。事实上,Ceph正是须要有目的的利用这种动态映射关系。正是利用了CRUSH的动态特性,Ceph能够将一个PG根据须要动态迁移到不一样的OSD组合上,从而自动化地实现高可靠性、数据分布re-blancing等特性。
之因此在这次映射中使用CRUSH算法,而不是其余哈希算法,缘由之一正是CRUSH具备上述可配置特性,能够根据管理员的配置参数决定OSD的物理位置映射策略;另外一方面是由于CRUSH具备特殊的“稳定性”,也即,当系统中加入新的OSD,致使系统规模增大时,大部分PG与OSD之间的映射关系不会发生改变,只有少部分PG的映射关系会发生变化并引起数据迁移。这种可配置性和稳定性都不是普通哈希算法所能提供的。所以,CRUSH算法的设计也是Ceph的核心内容之一,具体介绍能够参考。
至此为止,Ceph经过三次映射,完成了从file到object、PG和OSD整个映射过程。通观整个过程,能够看到,这里没有任何的全局性查表操做需求。至于惟一的全局性数据结构cluster map,在后文中将加以介绍。能够在这里指明的是,cluster map的维护和操做都是轻量级的,不会对系统的可扩展性、性能等因素形成不良影响。
一个可能出现的困惑是:为何须要同时设计第二次和第三次映射?难道不重复么?关于这一点,Sage在其论文中解说很少,而笔者我的的分析以下:
咱们能够反过来想像一下,若是没有PG这一层映射,又会怎么样呢?在这种状况下,必定须要采用某种算法,将object直接映射到一组OSD上。若是这种算法是某种固定映射的哈希算法,则意味着一个object将被固定映射在一组OSD上,当其中一个或多个OSD损坏时,object没法被自动迁移至其余OSD上(由于映射函数不容许),当系统为了扩容新增了OSD时,object也没法被re-balance到新的OSD上(一样由于映射函数不容许)。这些限制都违背了Ceph系统高可靠性、高自动化的设计初衷。
若是采用一个动态算法(例如仍然采用CRUSH算法)来完成这一映射,彷佛是能够避免静态映射致使的问题。可是,其结果将是各个OSD所处理的本地元数据量爆增,由此带来的计算复杂度和维护工做量也是难以承受的。
例如,在Ceph的现有机制中,一个OSD平时须要和与其共同承载同一个PG的其余OSD交换信息,以肯定各自是否工做正常,是否须要进行维护操做。因为一个OSD上大约承载数百个PG,每一个PG内一般有3个OSD,所以,一段时间内,一个OSD大约须要进行数百至数千次OSD信息交换。
然而,若是没有PG的存在,则一个OSD须要和与其共同承载同一个object的其余OSD交换信息。因为每一个OSD上承载的object极可能高达数百万个,所以,一样长度的一段时间内,一个OSD大约须要进行的OSD间信息交换将暴涨至数百万乃至数千万次。而这种状态维护成本显然太高。
综上所述,笔者认为,引入PG的好处至少有二:一方面实现了object和OSD之间的动态映射,从而为Ceph的可靠性、自动化等特性的实现留下了空间;另外一方面也有效简化了数据的存储组织,大大下降了系统的维护管理开销。理解这一点,对于完全理解Ceph的对象寻址机制,是十分重要的。
此处将首先以file写入过程为例,对数据操做流程进行说明。
为简化说明,便于理解,此处进行若干假定。首先,假定待写入的file较小,无需切分,仅被映射为一个object。其次,假定系统中一个PG被映射到3个OSD上。
基于上述假定,则file写入流程能够被下图表示:
如图所示,当某个client须要向Ceph集群写入一个file时,首先须要在本地完成5.1节中所叙述的寻址流程,将file变为一个object,而后找出存储该object的一组三个OSD。这三个OSD具备各自不一样的序号,序号最靠前的那个OSD就是这一组中的Primary OSD,然后两个则依次是Secondary OSD和Tertiary OSD。
找出三个OSD后,client将直接和Primary OSD通讯,发起写入操做(步骤1)。Primary OSD收到请求后,分别向Secondary OSD和Tertiary OSD发起写入操做(步骤二、3)。当Secondary OSD和Tertiary OSD各自完成写入操做后,将分别向Primary OSD发送确认信息(步骤四、5)。当Primary OSD确信其余两个OSD的写入完成后,则本身也完成数据写入,并向client确认object写入操做完成(步骤6)。
之因此采用这样的写入流程,本质上是为了保证写入过程当中的可靠性,尽量避免形成数据丢失。同时,因为client只须要向Primary OSD发送数据,所以,在Internet使用场景下的外网带宽和总体访问延迟又获得了必定程度的优化。
固然,这种可靠性机制必然致使较长的延迟,特别是,若是等到全部的OSD都将数据写入磁盘后再向client发送确认信号,则总体延迟可能难以忍受。所以,Ceph能够分两次向client进行确认。当各个OSD都将数据写入内存缓冲区后,就先向client发送一次确认,此时client便可以向下执行。待各个OSD都将数据写入磁盘后,会向client发送一个最终确认信号,此时client能够根据须要删除本地数据。
分析上述流程能够看出,在正常状况下,client能够独立完成OSD寻址操做,而没必要依赖于其余系统模块。所以,大量的client能够同时和大量的OSD进行并行操做。同时,若是一个file被切分红多个object,这多个object也可被并行发送至多个OSD。
从OSD的角度来看,因为同一个OSD在不一样的PG中的角色不一样,所以,其工做压力也能够被尽量均匀地分担,从而避免单个OSD变成性能瓶颈。
若是须要读取数据,client只需完成一样的寻址过程,并直接和Primary OSD联系。目前的Ceph设计中,被读取的数据仅由Primary OSD提供。但目前也有分散读取压力以提升性能的讨论。
前面的介绍中已经提到,由若干个monitor共同负责整个Ceph集群中全部OSD状态的发现与记录,而且共同造成cluster map的master版本,而后扩散至全体OSD以及client。OSD使用cluster map进行数据的维护,而client使用cluster map进行数据的寻址。
在集群中,各个monitor的功能整体上是同样的,其相互间的关系能够被简单理解为主从备份关系。所以,在下面的讨论中不对各个monitor加以区分。
略显出乎意料的是,monitor并不主动轮询各个OSD的当前状态。正相反,OSD须要向monitor上报状态信息。常见的上报有两种状况:一是新的OSD被加入集群,二是某个OSD发现自身或者其余OSD发生异常。在收到这些上报信息后,monitor将更新cluster map信息并加以扩散。其细节将在下文中加以介绍。
Cluster map的实际内容包括:
(1) Epoch,即版本号。Cluster map的epoch是一个单调递增序列。Epoch越大,则cluster map版本越新。所以,持有不一样版本cluster map的OSD或client能够简单地经过比较epoch决定应该听从谁手中的版本。而monitor手中一定有epoch最大、版本最新的cluster map。当任意两方在通讯时发现彼此epoch值不一样时,将默认先将cluster map同步至高版本一方的状态,再进行后续操做。
(2)各个OSD的网络地址。
(3)各个OSD的状态。OSD状态的描述分为两个维度:up或者down(代表OSD是否正常工做),in或者out(代表OSD是否在至少一个PG中)。所以,对于任意一个OSD,共有四种可能的状态:
—— Up且in:说明该OSD正常运行,且已经承载至少一个PG的数据。这是一个OSD的标准工做状态;
—— Up且out:说明该OSD正常运行,但并未承载任何PG,其中也没有数据。一个新的OSD刚刚被加入Ceph集群后,便会处于这一状态。而一个出现故障的OSD被修复后,从新加入Ceph集群时,也是处于这一状态;
—— Down且in:说明该OSD发生异常,但仍然承载着至少一个PG,其中仍然存储着数据。这种状态下的OSD刚刚被发现存在异常,可能仍能恢复正常,也可能会完全没法工做;
—— Down且out:说明该OSD已经完全发生故障,且已经再也不承载任何PG。
(4)CRUSH算法配置参数。代表了Ceph集群的物理层级关系(cluster hierarchy),位置映射规则(placement rules)。
根据cluster map的定义能够看出,其版本变化一般只会由(3)和(4)两项信息的变化触发。而这二者相比,(3)发生变化的几率更高一些。这能够经过下面对OSD工做状态变化过程的介绍加以反映。
一个新的OSD上线后,首先根据配置信息与monitor通讯。Monitor将其加入cluster map,并设置为up且out状态,再将最新版本的cluster map发给这个新OSD。
收到monitor发来的cluster map以后,这个新OSD计算出本身所承载的PG(为简化讨论,此处咱们假定这个新的OSD开始只承载一个PG),以及和本身承载同一个PG的其余OSD。而后,新OSD将与这些OSD取得联系。若是这个PG目前处于降级状态(即承载该PG的OSD个数少于正常值,如正常应该是3个,此时只有2个或1个。这种状况一般是OSD故障所致),则其余OSD将把这个PG内的全部对象和元数据复制给新OSD。数据复制完成后,新OSD被置为up且in状态。而cluster map内容也将据此更新。这事实上是一个自动化的failure recovery过程。固然,即使没有新的OSD加入,降级的PG也将计算出其余OSD实现failure recovery。
若是该PG目前一切正常,则这个新OSD将替换掉现有OSD中的一个(PG内将从新选出Primary OSD),并承担其数据。在数据复制完成后,新OSD被置为up且in状态,而被替换的OSD将退出该PG(但状态一般仍然为up且in,由于还要承载其余PG)。而cluster map内容也将据此更新。这事实上是一个自动化的数据re-balancing过程。
若是一个OSD发现和本身共同承载一个PG的另外一个OSD没法联通,则会将这一状况上报monitor。此外,若是一个OSD deamon发现自身工做状态异常,也将把异常状况主动上报给monitor。在上述状况下,monitor将把出现问题的OSD的状态设为down且in。若是超过某一预订时间期限,该OSD仍然没法恢复正常,则其状态将被设置为down且out。反之,若是该OSD可以恢复正常,则其状态会恢复为up且in。在上述这些状态变化发生以后,monitor都将更新cluster map并进行扩散。这事实上是自动化的failure detection过程。
由以前介绍能够看出,对于一个Ceph集群而言,即使由数千个甚至更多OSD组成,cluster map的数据结构大小也并不惊人。同时,cluster map的状态更新并不会频繁发生。即使如此,Ceph依然对cluster map信息的扩散机制进行了优化,以便减轻相关计算和通讯压力。
首先,cluster map信息是以增量形式扩散的。若是任意一次通讯的双方发现其epoch不一致,则版本更新的一方将把两者所拥有的cluster map的差别发送给另一方。
其次,cluster map信息是以异步且lazy的形式扩散的。也即,monitor并不会在每一次cluster map版本更新后都将新版本广播至全体OSD,而是在有OSD向本身上报信息时,将更新回复给对方。相似的,各个OSD也是在和其余OSD通讯时,将更新发送给版本低于本身的对方。
基于上述机制,Ceph避免了因为cluster map版本更新而引发的广播风暴。这虽然是一种异步且lazy的机制,但根据Sage论文中的结论,对于一个由n个OSD组成的Ceph集群,任何一次版本更新可以在O(log(n))时间复杂度内扩散到集群中的任何一个OSD上。
一个可能被问到的问题是:既然这是一种异步和lazy的扩散机制,则在版本扩散过程当中,系统一定出现各个OSD看到的cluster map不一致的状况,这是否会致使问题?答案是:不会。事实上,若是一个client和它要访问的PG内部的各个OSD看到的cluster map状态一致,则访问操做就能够正确进行。而若是这个client或者PG中的某个OSD和其余几方的cluster map不一致,则根据Ceph的机制设计,这几方将首先同步cluster map至最新状态,并进行必要的数据re-balancing操做,而后便可继续正常访问。
经过上述介绍,咱们能够简要了解Ceph到底是若是基于cluster map机制,并由monitor、OSD和client共同配合完成集群状态的维护与数据访问的。特别的,基于这个机制,事实上能够天然而然的完成自动化的数据备份、数据re-balancing、故障探测和故障恢复,并不须要复杂的特殊设计。这一点确实让人印象深入。