Redhat Ceph存储之深入理解Ceph架构.docx
《Redhat Ceph存储之深入理解Ceph架构.docx》由会员分享,可在线阅读,更多相关《Redhat Ceph存储之深入理解Ceph架构.docx(24页珍藏版)》请在冰点文库上搜索。
RedhatCeph存储之深入理解Ceph架构
RedhatCeph存储之“深入理解Ceph架构”
第1章概览
第2章存储集群架构
2.1存储池
2.2身份认证
2.3PG(s)
2.4CRUSH
2.5I/O操作
2.5.1副本I/O
2.5.2纠删码I/O
2.6自管理的内部操作
2.6.1心跳
2.6.2同步
2.6.3数据再平衡与恢复
2.6.4校验(或擦除)
2.7高可用
2.7.1数据副本
2.7.2Mon集群
2.7.3CephX
第3章客户端架构
3.1本地协议与Librados
3.2对象的监视与通知
3.3独占锁
3.4对象映射索引
3.5数据条带化
第4章加密
第1章概览
RedHatCeph是一个分布式的数据对象存储,系统设计旨在性能、可靠性和可扩展性上能够提供优秀的存储服务。
分布式对象存储是存储的未来,因为它们适应非结构化数据,并且客户端可以同时使用现代及传统的对象接口进行数据存取。
例如:
·本地语言绑定接口(C/C++、Java、Python)
·RESTful接口(S3/Swift)
·块设备接口
·文件系统接口
RedHatCeph所具备的强大功能可以改变您公司(或组织)的IT基础架构和管理海量数据的能力,特别是对于像RHELOSP这样的云计算平台。
RedHatCeph具有非常好的可扩展性——数以千计的客户端可以访问PB级到EB级甚至更多的数据。
译者注:
数据的规模可以用KB、MB、GB、TB、PB、EB、YB等依次表示,比如1TB=1024GB。
每一个Ceph部署的核心就是Ceph存储集群。
集群主要是由2类后台守护进程组成:
·CephOSD守护进程:
CephOSD为Ceph客户端存储数据提供支持。
另外,CephOSD利用Ceph节点的CPU和内存来执行数据复制、数据再平衡、数据恢复、状态监视以及状态上报等功能。
·Ceph监视器:
Ceph监视器使用存储集群的当前状态维护Ceph存储集群映射关系的一份主副本。
Ceph客户端接口与Ceph存储集群进行数据读写上的交互。
客户端要与Ceph存储集群通信,则需要具备以下条件:
·Ceph配置文件,或者集群名称(通常名称为ceph)与监视器地址
·存储池名称
·用户名及密钥所在路径
Ceph客户端维护对象ID和存储对象的存储池名称,但它们既不需要维护对象到OSD的索引,也不需要与一个集中的对象索引进行通信来查找数据对象的位置。
为了能够存储并获取数据,Ceph客户端首先会访问一台Cephmon并得到最新的存储集群映射关系,然后Ceph客户端可以通过提供的对象名称与存储池名称,使用集群映射关系和CRUSH算法(可控的、可扩展的、分布式的副本数据放置算法)来计算出提供对象所在的PG和主CephOSD,最后,Ceph客户端连接到可执行读写操作的主OSD上进而达到数据的存储与获取。
客户端和OSD之间没有中间服务器,中间件或总线。
当一个OSD需要存储数据时(无论客户端是CephBlock设备,Ceph对象网关或其他接口),从客户端接收数据然后将数据存储为对象。
每一个对象相当于文件系统中存放于如磁盘等存储设备上的一个文件。
注:
一个对象的ID在整个集群中是唯一的,(全局唯一)而不仅仅是本地文件系统中的唯一。
CephOSD将所有数据作为对象存储在扁平结构的命名空间中(例如,没有目录层次结构)。
对象在集群范围内具有唯一的标识、二进制数据、以及由一组名称/值的键值对组成的元数据。
而这些语义完全取决于Ceph的客户端。
例如,Ceph块设备将块设备镜像映射到集群中存储的一系列对象上。
注:
由唯一ID、数据、名称/值构成键值对的元数据组成的对象可以表示结构化和非结构化数据,以及前沿新的数据存储接口或者原始老旧的数据存储接口。
第2章存储集群架构
为了有效的实现无限可扩展性、高可用性以及服务性能,Ceph存储集群可以包含大量的Ceph节点。
每个节点利用商业硬件以及智能的Ceph守护进程实现彼此之间的通信:
·存储和检索数据
·数据复制
·监控并报告集群运行状况(心跳)
·动态的重新分布数据(回填)
·确保数据完整性(清理及校验)
·失败恢复
对于读写数据的Ceph客户端接口来说,Ceph存储集群看起来就像一个存储数据的简单存储池。
然而,存储集群背后却是对客户端接口完全透明的方式并且会执行许多复杂的操作。
Ceph客户端和CephOSD都使用CRUSH算法(可控的、可扩展的、分布式的副本数据放置算法),后面的章节会详细讲解CRUSH算法。
2.1存储池
Ceph存储集群通过‘存储池’这一逻辑划分的概念对数据对象进行存储。
可以为特定类型的数据创建存储池,比如块设备、对象网关,亦或仅仅是为了将一组用户与另一组用户分开。
从Ceph客户端来看,存储集群非常简单。
当有Ceph客户端想读写数据时(例如,会调用I/O上下文),客户端总是会连接到存储集群中的一个存储池上。
客户端指定存储池名称、用户以及密钥,所以存储池会充当逻辑划分的角色,这一角色使得对数据对象访问进行控制。
实际上,存储池不只是存储对象数据的逻辑划分,它还扮演着Ceph存储集群是如何分布及存储数据的角色,当然了,这些复杂的操作对客户端来说也是透明的。
Ceph存储池定义了:
·存储池类型:
在以前的老版本中,一个存储池只是简单的维护对象的多个深拷贝。
而现在,Ceph能够维护一个对象的多个副本,或者能够使用纠删码。
正因为保证数据持久化的2种方法(副本方式与纠删码方式)存在差异,所以Ceph支持存储池类型。
存储池类型对于客户端也是透明的。
·PG:
在EB规模的存储集群中,一个Ceph存储池可能会存储数百万或更多的数据对象。
因为Ceph必须处理数据持久化(副本或纠删码数据块)、清理校验、复制、重新再平衡以及数据恢复,因此在每个对象基础上的管理就会出现扩展性和性能上的瓶颈。
Ceph通过散列存储池到PG的方式来解决这个瓶颈问题。
CRUSH则分配每一个对象到指定的PG中,每个PG再到一组OSD中。
·CRUSH规则集:
Ceph中,高可用、持久化能力以及性能是非常重要的。
CRUSH算法计算用于存储对象的PG,同时也用于计算出PG的OSDActingSet
译者注:
actingset即为活跃的osd集合,集合中第一个编号的osd即为主primaryOSD。
·CRUSH也扮演着其他重要角色:
即CRUSH可以识别故障域和性能域(例如,存储介质类型、nodes,racks,rows等等)。
CRUSH使得客户端可以跨故障域(rooms,racks,rows等等)完成数据的写入以便当节点出现粒度比较大的问题时(例如,rack出问题)集群仍然可以以降级的状态提供服务直至集群状态恢复。
CRUSH也可使客户端能够将数据写入特定类型的硬件中(性能域),例如SSD或具有SSD日志的硬盘驱动器,亦或具有与数据驱动相同驱动的日志硬盘驱动器。
对于存储池来说,CRUSH规则集决定了故障域以及性能域。
·数据持久化方式:
在EB规模的存储集群中,硬件故障因为可预期所以一般并不算异常。
当使用数据对象表示较大粒度的存储接口时(例如块设备),对于这种大粒度存储接口来说,对象的丢失(不管是1个还是多个)都可能破坏数据的完整性进而导致数据不可用。
因此,数据丢失是不可容忍也是不能接受的。
Ceph提供了2种持久化方式:
第1种为副本存储池方式,这种方式将多份相同内容的数据对象通过CRUSH进行故障域的隔离来存储到不同的节点上(比如将对象分别存储在硬件相互隔离的不同节点上),这样即使硬件问题也不会对数据的持久化能力产生什么大的影响;第2种为纠删码存储池方式,这种方式将对象存储到K+M 个块中,其中K表示数据块,M 表示编码块。
K+M的和表示总的OSD数量,可以支持最多同时有M 个OSD出现问题,数据也不会丢失。
从客户端角度来看,Ceph对外呈现显得优雅而简单。
客户端只需要读取或写入数据到存储池。
但是,存储池在数据持久化,性能以及高可用方面发挥着重要的作用。
2.2身份认证
为了识别用户并防止中间人攻击,Ceph提供了cephx认证系统来验证用户和守护进程。
注:
Cephx协议并不处理传输中的数据加密(例如SSL/TLS)也不处理静态数据加密。
Cephx使用共享的密钥进行认证,这也意味着客户端和mon都会有客户端密钥副本。
认证协议也就是双方都能够向对方证明他们拥有密钥的副本,而不会实际泄露密钥。
这种方式提供了相互认证的机制,意味着集群确信用户拥有密钥以及用户确信集群拥有密钥的副本。
2.3PG(s)
Ceph将存储池分片处理成在集群中均匀且伪随机分布的PG。
CRUSH算法将每个对象分配到一个指定的PG中,并且将每个PG分配到对应的ActingSet集合中—也就是在Ceph客户端和存储对象副本的OSD之间创建一个间接层。
如果Ceph客户端直接就能知道对象存放到具体的哪个OSD中的话,那么Ceph客户端和CephOSD之间耦合性就太强了。
相反的,CRUSH算法会动态的将对象分配到PG中,然后再将PG分配到一组Ceph的OSD中。
有了这个间接层之后,当新CephOSD加入或者CephOSD出现问题时,Ceph存储集群就可以动态的进行数据再平衡。
通过在数百到数千个放置组的环境中管理数百万个对象,Ceph存储集群可以高效地增长和收缩以及从故障中恢复。
下面的图描述了CRUSH是如何将对象分配到PG中,以及PG分配到OSD中的。
相对整体集群规模来说,如果存储池设置的PG较少,那么在每个PG上Ceph将会存储大量的数据;如果存储池设置的PG过大,那么CephOSD将会消耗更多的CPU与内存,不管哪一种情况都不会有较好的处理性能。
所以,为每个存储池设置适当数量的PG,以及分配给集群中每个OSD的PG数量的上限对Ceph性能至关重要。
译者注:
PG是对象的集合,在同一个集合里的对象放置规则都一样(比如同一集合中的对象统一都存储到osd.1、osd.5、osd.8这几台机器中);同时,一个对象只能属于一个PG,而一个PG又对应于所放置的OSD列表;另外就是每个OSD上一般会分布很多个PG。
2.4CRUSH
Ceph会将CRUSH规则集分配给存储池。
当Ceph客户端存储或检索存储池中的数据时,Ceph会自动识别CRUSH规则集、以及存储和检索数据这一规则中的顶级bucket。
当Ceph处理CRUSH规则时,它会识别出包含某个PG的主OSD,这样就可以使客户端直接与主OSD进行连接进行数据的读写。
为了将PG映射到OSD上,CRUSH映射关系定义了bucket类型的层级列表(例如在CRUSH映射关系中的types以下部分)。
创建bucket层级结构的目的是通过其故障域和(或)性能域(例如驱动器类型、hosts、chassis、racks、pdu、pods、rows、rooms、datacenters)来隔离叶子节点。
除了代表OSD的叶子节点之外,层次结构的其余部分可以是任意的,如果默认类型不符合你的要求,可以根据自己的需要来定义它。
CRUSH支持一个有向无环图的拓扑结构,它可以用来模拟你的CephOSD节点在层级结构中的分布情况。
因此,可以在单个CRUSH映射关系中支持具有多个Root节点的多个层级结构。
例如,可以创建SSD的层级结构、使用SSD日志的硬盘层级结构等等。
译者注:
CRUSH的目的很明确,就是一个PG如何与OSD建立起对应的关系。
2.5I/O操作
Ceph客户端从Cephmon获取‘集群映射关系Clustermap,然后对存储池中的对象执行I/O操作。
对于Ceph如何将数据存于目标中来说,存储池的CRUSH规则集和PG数的设置起主要的作用。
拥有最新的集群映射关系,客户端就会知道集群中所有的mon和OSD的信息。
但是,客户端并不知道对象具体的存储位置(不知道对象具体存在哪个OSD上)。
对于客户端来说,需要的输入参数仅仅是对象ID和存储池名称。
逻辑上也比较简单:
Ceph将数据存储在指定名称的存储池中(例如存储池名称为livepool)。
当客户端想要存储一个对象时(比如对象名叫“john”、“paul”、"george”、“ringo”等),客户端则会以对象名、根据对象名信息计算的hash码、存储池中的PG数、以及存储池名称这些信息作为输入参数,然后CRUSH(可控的、可扩展的、分布式的副本数据放置算法)就会计算出PG的ID(PG_ID)及PG对应的主OSD信息。
译者注:
根据设置的副本数(比如3副本)则计算出的列表如(osd.1、osd.3、osd.8),这里的第一个osd.1就是主OSD。
Ceph客户端经过以下步骤来计算出PGID信息。
1.客户端输入存储池ID以及对象ID(例如,存储池pool=”liverpool”,对象ID=”john”)。
2.CRUSH获取对象ID后对其进行HASH编码。
3.CRUSH根据上一步的HASH编码与PG总数求模后得到PG的ID。
(译者注:
例如HASH编码后为186,而PG总数为128,则求模得58,所以这个对象会存储在PG_58中;另外这也可以看出PG数对存储的影响,因为涉及到对象与PG的映射关系,所以轻易不要调整PG数)
4.CRUSH计算对应PGID的主OSD。
5.客户端根据存储池名称得到存储池ID(例如”liverpool”=4)。
6.客户端将PGID与存储池ID拼接(例如 4.58)
7.客户端直接与ActivtinSet集合中的主OSD通信,来执行对象的IO操作(例如,写入、读取、删除等)。
译者注:
Pool的名称与ID(ID=4,存储池名称为default.rgw.log)。
Ceph存储集群的拓扑和状态在会话(I/O上下文)期间相对比较稳定。
与客户端在每个读/写操作的会话上查询存储相比,Ceph客户端计算对象存储位置的速度要更快些。
CRUSH算法不但能使客户端可以计算出对象应当存储的位置,同时也使得客户端可以和ActingSet集合中的主OSD直接交互来实现对象的存储与检索。
由于EB规模的存储集群一般会有数千个OSD存储节点,所以客户端与CephOSD之间的网络交互并不是什么大的问题。
即使集群状态发生变化,客户端也可以通过Cephmon查询到更新的集群映射关系。
2.5.1副本I/O
和Ceph客户端一样,CephOSD也是通过与Cephmon交互来获取到最新的集群映射关系。
CephOSD也使用CRUSH算法,但是用这个算法是用来计算对象的副本应该存储在什么位置(译者注:
客户端用CRUSH是用来找主OSD以及计算出ActingSet列表,而OSD用CRUSH则是主OSD定位对应的副本是谁)。
在典型的写操作场景下,Ceph客户端使用CRUSH算法计算对象所在的PGID以及ActingSet列表中的主OSD,当客户端将对象写到主OSD时,主OSD会查看这个对象应该存储的副本个数(例如,osd_pool_default_size=n),然后主OSD根据对象ID、存储池名称、集群映射关系这些信息再根据CRUSH算法来计算出ActingSet列表中的从属OSD(译者注:
除列表中第一个OSD外,其它的都是从属OSD)。
主OSD将对象写入从属OSD中,当主OSD收到从属OSD回复的ACK确认并且主OSD自身也完成了写操作后,主OSD才会给Ceph客户端回复真正写入成功的ACK确认。
通过有代表性的Ceph客户端(主OSD)执行数据复制的能力,CephOSD守护进程相对的减轻了Ceph客户端的这一职责,同时确保了数据高可用以及安全性。
注:
比较典型的就是主OSD和从属OSD在部署时会将故障域进行隔离(比如不同时配置到一个rack上或一个row上,亦或是同一个node上)。
CRUSH计算从属OSD的ID也会考虑故障域信息。
2.5.2纠删码I/O
纠删码实际上是一种前向错误纠正编码,这种编码会将K个数据块通过补充N个编码块的方式,将原始数据扩展为更长的消息编码,以便当N个数据块出现问题时数据依旧不会丢失。
随着时间的推移,开发了不同的纠删编码算法,其中最早和最常用的算法之一是Reed-Solomon算法。
可以通过等式 N=K+M 对这一算法进行理解,等式中 K 表示数据块的个数,M 代表了编码块的个数,而 N 则是在 纠删编码 过程中创建的总的块的个数。
值 M 可以简化为 N–K ,也就是说在计算原始的K个数据块时 N–K 个冗余块也一并需要计算出来。
这种方法保证只要N个块中的K有效就可以访问所有原始数据。
换句话说,即使有 N–K 个块出现了故障,对外提供服务的数据仍旧是没有问题的。
例如配置(N=16,K=10)或者纠删编码10/16,10个基本的块(K)中会有额外补充的6个块( M=K-N,如16-10=6 )。
这16个块(N)可能对应16个OSD。
即使有6个OSD出现问题,原始文件也可以从这10个已经验证的数据块中重建恢复。
这就意味着不会有任何的数据丢失,因此纠删码也具备比较高的容错能力。
和副本存储池类似,纠删码存储池也是由upset列表中的主OSD来接收所有的写操作。
在副本存储池中,Ceph对PG中的每个对象在从属OSD上都会有一份一样的数据对象;而对于纠删码存储池来说,可能略有不同。
每个纠删码存储池都会以 K+M 个块来存储每一个对象。
对象(的数据内容)会被切分成 K 个数据块以及 M个编码块。
纠删码存储池创建时也需要配置成 K+M 的大小(size)以便每个块都可以存储到ActivtinSet列表中的每个OSD上。
对象的属性存储这些块的等级。
主OSD负责数据划分到 K+M 个块的纠删编码以及将这些编码信息发送到其它的OSD上。
同时主OSD也会维护PG的权威日志(译者注:
权威日志实际是一种进度控制机制,尤其当某些节点出现问题时,可以根据权威日志进行数据的恢复)。
例如,使用5个OSD (K+M=5) 创建纠删码存储池,支持其中2个 (M=2) 块的数据丢失。
将对象写入纠删码存储池中的时候(比如对象名叫 NYAN,内容为 ABCDEFGHI )纠删码计算函数会将对象的内容按长度平分成3个块(即,分成K个数据块),第一个块内容为 ABC ,第二个块内容为DEF ,第三个块内容为 GHI ,如果块内长度不是 K 的倍数,那么平分后最后的一块所剩余的空位就会进行填充以使其长度为K(比如内容串为ABCDEFGHIJ,则3个数据块内容依次为ABCD、EFGH、IJ..,最后的IJ长度不够就会填充);除了将内容按K切分外,纠删码函数也要创建另外2个编码块,即第4个块内容为 XYZ ,第5个块内容为 GQC 。
这里的每一个块内容都对应ActionSet列表中的一个OSD。
这些块有相同的名称都叫 NYAN ,但块存在不同的OSD中。
除了名称之外,数据块创建的对应序号需要存储在对象的属性中( shard_t )。
包括 ABC 内容的第一个块存储在 OSD5 上,而包括 YXY 内容的第4个块则存储在 OSD3 上。
译者注:
注意上图中,5个块的名称都叫NYAN,每个块的内容为K个均分的内容,同时被切分后的每个块都有一个唯一序号shard,每个块都对应不同的OSD,即块按HOST进行故障域隔离。
译者注:
比如以下配置及图例中,K=4,M=2并且以rack作为故障域)
如果从纠删码存储池中读取对象 NYAN,解码函数需要读取3个块:
包括ABC 的第一个块,包括GHI 的第3个块以及包括YXY 的第4个块;然后重构出对象的内容ABCDEFGHI 。
解码函数来通知第2个块和第5个块缺失(一般称为纠删或擦写)。
可在这2个缺失的块中,第5个块缺失可能因为OSD4 状态是OUT而读不到,只要读到3个块可读的话,解码函数就可以被调用:
因为OSD2对应的是最慢的块,所以读取时排除掉不在考虑之内。
将数据拆分成不同的块是独立于对象放置规则的。
CRUSH规则集和纠删码存储池配置决定了块在OSD上的放置。
例如,在配置中如果使用lrc(局部可修复编码)插件来创建额外块的话,那么恢复数据的话则需要更少的OSD。
例如lrc配置信息:
K=4、M=2、L=3 中,使用jerasure插件库来创建6个块(K+M),但局部值(L=3 )则要求需要再创建2个局部块。
额外创建的局部块个数可以通过(K+M)/L 来计算得出。
如果0号块的OSD出现问题,那么这个块的数据可以通过块1,块2以及第一个局部块进行恢复。
在这个例子中,恢复也只需要3个块而不是5个块。
关于CRUSH、纠删码配置、以及插件的内容,可以参考存储策略指南。
注:
纠删码存储池的对象映射是失效的,不能设置为有效状态。
关于对象映射的更多内容,可以参考对象映射章节。
注:
纠删码存储池目前公支持RADOS网关(RGW),对于RADOS的块设备(RBD)目前还不支持。
2.6自管理的内部操作
Ceph集群也会自动的执行一些自身状态相关的监控与管理工作。
例如,Ceph的OSD可以检查集群的健康状态并将结果上报给后端的Cephmon;再比如,通过CRUSH算法将对象映射到PG上,再将PG映射到具体的OSD上;同时,CephOSD也通过CRUSH算法对OSD的故障等问题进行自动的数据再平衡以及数据恢复。
以下部分我们将介绍Ceph执行的一些操作。
2.6.1心跳
CephOSD加入到集群中并且将其状态上报到Cephmon。
在底层实现上,CephOSD的状态就是up或为down ,这一状态反映的就是OSD是否运行并为Ceph客户端的请求提供服务。
如果CephOSD在集群中的状态是donw且为in ,那么表明此OSD是有问题不能提供服务的;如果CephOSD并没有运行(比如服务crash掉了),那么这个CephOSD也不能上报给Cephmon其自身状态为Down 。
Cephmon会定期的ping这些OSD以此来确信这些OSD是否仍在运行。
当然了,Ceph也提供了更多的机制,比如使CephOSD可以评判与之关联的OSD是否状态为down(译者注:
比如在副本OSD间相互ping状态的关系,没有副本关系的话,OSD之间不会建立连接亦即更不会ping彼此),以及更新Ceph的集群映射关系并上报给Cephmon。
由于OSD分担了部分工作,所以对于Cephmon来说,工作内容相对要轻量很多。
2.6.2同步
CephOSD守护进程执行同步,这里的同步指的是将存储放置组(PG)的所有OSD中对象状态(包括元数据信息)达到一致的过程。
同步问题通常都会自行解决无需人为的干预。
注:
即使Cephmon对于OSD存储PG的状态达成一致,这也并不意味着PG拥有最新的内容。
当Ceph存储PG到OSD的actingset列表中的时候,会将它们分别标记为主,从等等。
惯例上,Actingset列表中的第一个是主OSD,主OSD也负责协调组内的PG进行同步操作,这里的主OSD也是唯一 接收客户端的写入对象到给定PG请求的OSD。
当一系列的OSD负责一个放置组PG,则这一系列的OSD,我们称它们为一个ActingSet。
ActingSet可能指的是当前负责放置组的CephOSD守护进程或者某个有效期内,负责特定放置组的OSD守护