Ceph架构剖析

e**分布式存储系统——Ceph**
1.Ceph的结构
Ceph架构剖析_第1张图片
从下到上将Ceph结构分为4层,分别介绍如下:
(1)基础存储系统——可靠的自动化分布式对象存储(RADOS)
所有存储在Ceph系统中的用户数据都在该层进行管理,而Ceph的高可靠、高可扩展、高性能、高自动化等等特性本质上也是由这一层所提供的。因此,理解RADOS是理解Ceph的基础与关键。RADOS在物理形态上由大量的存储设备节点组成,每个节点拥有自己的硬件资源(CPU、内存、硬盘、网络),并运行着操作系统和文件系统。

(2)基础库Librados
对RADOS的封装和抽象,向上层提供API,以便于直接基于RADOS进行开发。因为RADOS是一个对象存储系统,则Librados实现的API也主要是针对对象存储功能的。

(3)高级应用接口
这一层包括了三个部分:RADOS GW(RADOS Gateway)、 RBD(Reliable Block Device)和Ceph FS(Ceph File System),其作用是在librados库的基础上提供抽象层次更高、更便于应用或客户端使用的上层接口。

RADOS GW是一个提供与亚马逊S3和Swift兼容的RESTful API的gateway,以供相应的对象存储应用开发使用。RADOS GW提供的API抽象层次更高,但功能则不如librados强大。因此,开发者应针对自己的需求选择使用。

RBD则提供了一个标准的块设备接口,常用于在虚拟化的场景下为虚拟机创建volume。目前,Red Hat已经将RBD驱动集成在KVM/QEMU中,以提高虚拟机访问性能。

Ceph FS是一个POSIX兼容的分布式文件系统。

(4)应用层
这一层就是不同场景下对于Ceph各个应用接口的各种应用方式,例如基于librados直接开发的对象存储应用,基于RADOS GW开发的对象存储应用,基于RBD实现的云硬盘等等。

本节将对Ceph的工作原理和若干关键工作流程进行介绍。由于Ceph的功能实现本质上依托于RADOS,因此,此处的介绍事实上也是针对RADOS进行。对于上层的部分,特别是RADOS GW和RBD,由于现有的文档中(包括Sage的论文中)并未详细介绍,还请读者多多包涵。

2.RADOS的结构
RADOS的结构主要包括ObjectStorage Device(OSD),Monitor和MDS。
Ceph架构剖析_第2张图片

ObjectStorage Device(OSD)负责存储数据,处理数据复制、数据恢复、数据再均衡以及通过心跳机制监测其它OSD状况并报告给Ceph Monitors。

Monitor负责监控集群状态,包括监控自身状态、集群OSD状态、Placement Group(存储组织和位置映射PGs)状态、CRUSH状态(Controlled Replication Under Scalable Hashing,一种伪随机数据分布算法)。同时,Monitor还会记录它们的每一个历史状态改变版本信息,以确定集群该遵循哪个版本。

MDS负责文件系统的元数据存储和管理,块存储和对象存储服务是不需要这个模块的。MDS负责提供标准的POSIX文件访问接口。

3.RADOS的寻址机制
Ceph架构剖析_第3张图片

(1)概念说明
File:此处的file就是用户需要存储或者访问的文件。对于一个基于Ceph开发的对象存储应用而言,这个file也就对应于应用中的“对象“,也就是用户直接操作的“对象”。

objects:​此处的object是RADOS所看到的“对象”。Object与上面提到的file的区别是,object的最大size由RADOS限定(通常为2MB或4MB),以便实现底层存储的组织管理。因此,当上层应用向RADOS存入size很大的file时,需要将file切分成统一大小的一系列object(最后一个的大小可以不同)进行存储。

PGs(Placement Group)​:即安置组,对object的存储进行组织和位置映射。一个PG负责组织若干个object,但是一个object只能映射到一个PG中,即PG和object之间的关系是“一对多”。一个PG会被映射到多个OSD上,每个OSD上都会承载若干个PG,即PG和OSD之间的关系是“多对多”。

OSD(object storage device):OSD的数量事实上也关系到系统的数据分布均匀性,因此其数量不应太少。在实践当中,至少也应该是数十上百个的量级才有助于Ceph系统的设计发挥其应有的优势,一般是10-1000个。

(2)寻址的三层映射
<1>File -> object映射
这次映射的目的是,将用户要操作的file,映射为RADOS能够处理的object。其映射十分简单,本质上就是按照object的最大size对file进行切分。这种切分的好处有两点:一是让大小不限的file变成与最大size一致,方便RADOS底层高效管理;二是让对单一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的唯一性必须得到保证,否则后续映射无法正确进行。一般用MD5值作为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之间的映射关系才是固定不变的

之所以在此次映射中使用CRUSH算法,而不是其他哈希算法,原因之一正是CRUSH具有可配置特性,可以根据管理员的配置参数决定OSD的物理位置映射策略;另一方面是因为CRUSH具有特殊的”稳定性”。当系统中加入新的OSD,导致系统规模增大时,大部分PG与OSD之间的映射关系不会发生改变,只有少部分PG的映射关系会发生变化并引发数据迁移。这种可配置性和稳定性都不是普通哈希算法所能提供的。因此,CRUSH算法的设计也是Ceph的核心内容之一。

(3)思考:为什么要设计第二次和三次映射?
关于这一点,Sage在其论文中解说不多,参考网上一些资料再加上自己的理解,我觉得有下面几个原因:

反过来想一下,如果没有PG这一层映射,会怎样呢?
如果没有PG这一层的映射,就需要采用某一算法,直接将object映射到OSD上。

如果这一算法是某个固定的哈希算法,也就意味着一个object将被固定的映射到一组OSD中,当其中一个或多个OSD损坏时,object无法被自动迁移至其他OSD上(因为映射函数不允许),当系统为了扩容新增了OSD时,object也无法被re-balance到新的OSD上(同样因为映射函数不允许)。这些限制都违背了Ceph系统高可靠性、高自动化的设计初衷。

如果采用一个动态算法(例如仍然采用CRUSH算法)来完成这一映射,似乎是可以避免静态映射导致的问题。但是,其结果将是各个OSD所处理的本地元数据量爆增,由此带来的计算复杂度和维护工作量也是难以承受的。

综上所述,引入PG一方面实现了object和OSD之间的动态映射,从而为Ceph的可靠性、自动化等特性的实现留下了空间;另一方面也有效简化了数据的存储组织,大大降低了系统的维护管理开销。因此有了第二次(object->PG)和第三次(PG->OSD)的映射

4.数据操作流程——二次确认机制(强一致性)
Ceph架构剖析_第4张图片

假设:file较小,不需要进行分块,仅被映射为一个object,一个PG映射到3个OSD上。

(1)数据操作流程:

<1>file 先完成寻址流程,将file变为object,然后再找到存储该object的一组(3个)​OSD。
<2>​client 与主OSD(primary OSD)通信,写入数据。primary OSD在收到客户端的请求后向Secondary OSD、 Tertiary OSD发起写入数据的请求。
<3>​Secondary OSD、 Tertiary OSD写入操作完成后向Primary OSD发送操作完成的确认信息。
<4>当primary OSD也完成操作后就向客户端发送操作完成的确认信息。​文件的写操作完成。

之所以采用这样的写入流程,本质上是为了保证写入过程中的可靠性,尽可能避免造成数据丢失。同时,由于client只需要向Primary OSD发送数据,因此,在Internet使用场景下的外网带宽和整体访问延迟又得到了一定程度。

当然,这种可靠性机制必然导致较长的延迟,特别是,如果等到所有的OSD都将数据写入磁盘后再向client发送确认信号,则整体延迟可能难以忍受。

因此,Ceph可以分两次向client进行确认当各个OSD都将数据写入内存缓冲区后,就先向client发送一次确认,此时client即可以向下执行。待各个OSD都将数据写入磁盘后,会向client发送一个最终确认信号,此时client可以根据需要删除本地数据。

分析上述流程可以看出,在正常情况下,client可以独立完成OSD寻址操作,而不必依赖于其他系统模块。因此,大量的client可以同时和大量的OSD进行并行操作。同时,如果一个file被切分成多个object,这多个object也可被并行发送至多个OSD。

若需要读取数据,client只需完成同样的寻址过程,直接和Primary OSD联系。目前的Ceph设计中,被读取的数据仅由Primary OSD提供。但目前也有分散读取压力以提高性能的讨论。

5.集群的维护

由若干个monitor共同负责整个Ceph集群中所有OSD状态的发现与记录,并且共同形成cluster map的master版本,然后扩散至全体OSD以及client。OSD使用cluster map进行数据的维护,而client使用cluster map进行数据的寻址。在集群中,各个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以及和自己承载同一个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过程。

cluster map有以下几个特点:
(1)cluster map信息是以增量形式扩散的。如果任意一次通信的双方发现其epoch不一致,则版本更新的一方将把二者所拥有的cluster map的差异发送给另外一方。
(2)cluster map信息是以异步且lazy的形式扩散的。即monitor并不会在每一次cluster map版本更新后都将新版本广播至全体OSD,而是在有OSD向自己上报信息时,将更新回复给对方。类似的,各个OSD也是在和其他OSD通信时,将更新发送给版本低于自己的对方。

基于上述机制,Ceph避免了由于cluster map版本更新而引起的广播风暴。这虽然是一种异步且lazy的机制,但根据Sage论文中的结论,对于一个由n个OSD组成的Ceph集群,任何一次版本更新能够在O(log(n))时间复杂度内扩散到集群中的任何一个OSD上。

思考:既然cluster map消息扩散是一种异步和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、故障探测和故障恢复,并不需要复杂的特殊设计。
6.Ceph的特点
(1)高扩展性
高度并行。没有单个中心控制组件。所有负载都能动态的划分到各个服务器上。把更多的功能放到OSD上,让OSD更智能。

自管理。容易扩展、升级、替换。当组件发生故障时,自动进行数据的重新复制。当组件发生变化时(添加/删除),自动进行数据的重分布。

(2)高性能
<1>Client和Server直接通信,不需要代理和转发
<2>多个OSD带来的高并发度。objects是分布在所有OSD上。
<3>负载均衡。每个OSD都有权重值(现在以容量为权重)。
​<4>client不需要负责副本的复制(由primary OSD负责),这降低了client的网络消耗。
(3)高可靠性
<1>数据多副本。可配置的per-pool副本策略和故障域布局,支持强一致性。
<2>没有单点故障。可以忍受许多种故障场景;防止脑裂;单个组件可以滚动升级并在线替换.
<3>所有故障的检测和自动恢复。恢复不需要人工介入,在恢复期间,可以保持正常的数据访问。
<4>并行恢复。并行的恢复机制极大的降低了数据恢复时间,提高数据的可靠性。

你可能感兴趣的:(Ceph/GFS)