> 文档中心 > 【重识云原生】第三章云存储3.3节——Ceph统一存储方案

【重识云原生】第三章云存储3.3节——Ceph统一存储方案

接上文《【重识云原生】第三章云存储3.2节——SPDK方案综述》

        Ceph统一存储知识地图:

 1 Ceph项目简述

        Ceph最早起源于Sage就读博士期间的工作、成果于2004年发表,并随后贡献给开源社区。经过多年的发展之后,已得到众多云计算和存储厂商的支持,成为应用最广泛的开源分布式存储平台。

        Ceph根据场景可分为对象存储、块设备存储和文件存储。Ceph相比其它分布式存储技术,其优势点在于:它不单是存储,同时还充分利用了存储节点上的计算能力,在存储每一个数据时,都会通过计算得出该数据存储的位置,尽量将数据分布均衡。同时,由于采用了CRUSH、HASH等算法,使得它不存在传统的单点故障,且随着规模的扩大,性能并不会受到影响。

1.1 Ceph的特点

高性能

  • 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。
  • 考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。
  • 能够支持上千个存储节点的规模,支持TB到PB级的数据。

高可用性

  • 副本数可以灵活控制。
  • 支持故障域分隔,数据强一致性。
  • 多种故障场景自动进行修复自愈。
  • 没有单点故障,自动管理。

高可扩展性

  • 去中心化。
  • 扩展灵活。
  • 随着节点增加而线性增长。

特性丰富

  • 支持三种存储接口:块存储、文件存储、对象存储。
  • 支持自定义接口,支持多种语言驱动。
  • 当然,Ceph也存在一些缺点:
  • 去中心化的分布式解决方案,需要提前做好规划设计,对技术团队的要求能力比较高。
  • Ceph扩容时,由于其数据分布均衡的特性,会导致整个存储系统性能的下降。

2 Ceph的主要架构

  • Ceph的最底层是RADOS(分布式对象存储系统),它具有可靠、智能、分布式等特性,实现高可靠、高可拓展、高性能、高自动化等功能,并最终存储用户数据。RADOS系统主要由两部分组成,分别是OSD和Monitor。
  • RADOS之上是LIBRADOS,LIBRADOS是一个库,它允许应用程序通过访问该库来与RADOS系统进行交互,支持多种编程语言,比如C、C++、Python等。
  • 基于LIBRADOS层开发的有三种接口,分别是RADOSGW、librbd和MDS。
  • RADOSGW是一套基于当前流行的RESTFUL协议的网关,支持对象存储,兼容S3和Swift。
  • librbd提供分布式的块存储设备接口,支持块存储。
  • MDS提供兼容POSIX的文件系统,支持文件存储。

2.1 Ceph对对象存储的实现

        Ceph本质上是一个分布式对象存储系统,通过它的对象网关(object gateway),也就是RADOS网关(radosgw)提供对象存储接口。RADOS网关利用librgw(RADOS网关库)和librados这些库,允许应用程序跟Ceph对象存储建立连接。Ceph通过RESTful API提供可访问且最稳定的多租户对象存储解决方案之一。

        RADOS网关提供RESTful接口让用户的应用程序将数据存储到Ceph集群中。RADOS网关接口满足一下特点:

  • 兼容Swift:为OpenStack Swift API提供的对象存储功能;
  • 兼容S3:为Amazon S3 API提供的对象存储功能;
  • Admin API:这也称为管理API或者原生API,应用程序可以直接使用它来获取访问存储系统的权限以管理存储系统。

        要访问Ceph的对象存储系统,也可以绕开RADOS网关层,librados软件库允许用户的应用程序通过C、C++、Java、Python和PHP直接访问Ceph对象存储。

 2.2 Ceph对块存储实现

        在这种类型中,数据以块的形式存储在卷里,卷会挂接到节点上。这些块形成的卷会映射到操作系统中,并被文件系统层控制。

         Ceph引入了一个新的RBD协议,也就是Ceph块设备。RBD为客户端提供了可靠、分布式、高性能的块存储。RBD已经被Linux内核支持,几乎所有的Linux操作系统发行版都支持RBD。除了可靠性和性能之外,RBD也支持其他的企业级特性,如完整和增量式快照,精简的配置,写时复制式克隆以及全内存是缓存。

         Ceph RBD支持的最大镜像为16EB。这些镜像可以作为磁盘映射到物理机裸机、虚拟机或者其他主机用。业界领先的开源hypervisor,例如KVM和Xen完全支持RBD。​

2.3 Ceph对文件存储的实现

        Ceph文件系统(也就是CephFS)是一个兼容POSIX的文件系统,利用Ceph存储集群来保存用户数据。Linux内核驱动程序支持CephFS,这也使得CephFS高度适用于各大Linux操作系统发行版。CephFS将数据和元数据分开存储,为上层的应用程序提供较高的性能以及可靠性。

        在Ceph集群内部,Ceph文件系统库(libcephfs)运行在RADOS库(librados)之上,后者是Ceph存储集群协议,由文件、块和对象存储共用。要使用CephFS,集群节点上最少要配置一个Ceph元数据服务器(MDS),客户端可以采用多种方式使用CephFS。

       如果要把Ceph挂在成文件系统,客户端可以使用本地Linux内核的功能或者使用Ceph社区提供的ceph-fuse驱动。

        除此之外,客户端可以使用第三方开源程序,例如NFS的ganesha和SMB/CIFS的Samba。这些程序通过libcephfs将用户数据存入可靠的分布式Ceph存储集群。CephFS可以用来替代HDFS。也是通过libcephfs组件将数据存入Ceph集群。为了无缝实现这个功能,Ceph社区为Hadoop和Hadoop插件提供了必要的CephFS Java接口。

3 Ceph的功能模块

         Ceph的核心组件包括Client客户端、MON监控服务、MDS元数据服务、OSD存储服务,各组件功能如下:

  • Client客户端:负责存储协议的接入,节点负载均衡
  • MON监控服务:负责监控整个集群,维护集群的健康状态,维护展示集群状态的各种图表,如OSD Map、Monitor Map、PG Map和CRUSH Map
  • MDS元数据服务:负责保存文件系统的元数据,管理目录结构
  • OSD存储服务:主要功能是存储数据、复制数据、平衡数据、恢复数据,以及与其它OSD间进行心跳检查等。一般情况下一块硬盘对应一个OSD。

4 Ceph的资源划分

        Ceph采用crush算法,在大规模集群下,实现数据的快速、准确存放,同时能够在硬件故障或扩展硬件设备时,做到尽可能小的数据迁移,其原理如下:

  1. 当用户要将数据存储到Ceph集群时,数据先被分割成多个object,(每个object一个object id,大小可设置,默认是4MB),object是Ceph存储的最小存储单元。
  2. 由于object的数量很多,为了有效减少了Object到OSD的索引表、降低元数据的复杂度,使得写入和读取更加灵活,引入了pg(Placement Group ):PG用来管理object,每个object通过Hash,映射到某个pg中,一个pg可以包含多个object。
  3. Pg再通过CRUSH计算,映射到osd中。如果是三副本的,则每个pg都会映射到三个osd,保证了数据的冗余。

5 Ceph IO流程及数据分布

​5.1 正常IO流程图

步骤:

  1. client 创建cluster handler。
  2. client 读取配置文件。
  3. client 连接上monitor,获取集群map信息。
  4. client 读写io 根据crushmap 算法请求对应的主osd数据节点。
  5. 主osd数据节点同时写入另外两个副本节点数据。
  6. 等待主节点以及另外两个副本节点写完数据状态。
  7. 主节点及副本节点写入状态都成功后,返回给client,io写入完成。

5.2 新主IO流程图

说明:

        如果新加入的OSD1取代了原有的 OSD4成为 Primary OSD, 由于 OSD1 上未创建 PG , 不存在数据,那么 PG 上的 I/O 无法进行,怎样工作的呢?

步骤:

  1. client连接monitor获取集群map信息。
  2. 同时新主osd1由于没有pg数据会主动上报monitor告知让osd2临时接替为主。
  3. 临时主osd2会把数据全量同步给新主osd1。
  4. client IO读写直接连接临时主osd2进行读写。
  5. osd2收到读写io,同时写入另外两副本节点。
  6. 等待osd2以及另外两副本写入成功。
  7. osd2三份数据都写入成功返回给client, 此时client io读写完毕。
  8. 如果osd1数据同步完毕,临时主osd2会交出主角色。
  9. osd1成为主节点,osd2变成副本。

5.3 Ceph IO算法流程

        File用户需要读写的文件。File->Object映射:

a. ino (File的元数据,File的唯一id)。

b. ono(File切分产生的某个object的序号,默认以4M切分一个块大小)。

c. oid(object id: ino + ono)。

        

        Object是RADOS需要的对象。Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。Object->PG映射:

a. hash(oid) & mask -> pgid 。

b. mask = PG总数m(m为2的整数幂)-1 。

        

        PG(Placement Group),用途是对object的存储进行组织和位置映射, (类似于redis cluster里面的slot的概念) 一个PG里面会有很多object。采用CRUSH算法,将pgid代入其中,然后得到一组OSD。PG->OSD映射:

a. CRUSH(pgid)->(osd1,osd2,osd3) 。

5.4 Ceph IO伪代码流程

 5.5 Ceph RBD IO流程​

步骤:

  1. 客户端创建一个pool,需要为这个pool指定pg的数量。
  2. 创建pool/image rbd设备进行挂载。
  3. 用户写入的数据进行切块,每个块的大小默认为4M,并且每个块都有一个名字,名字就是object+序号。
  4. 将每个object通过pg进行副本位置的分配。
  5. pg根据cursh算法会寻找3个osd,把这个object分别保存在这三个osd上。
  6. osd上实际是把底层的disk进行了格式化操作,一般部署工具会将它格式化为xfs文件系统。
  7. object的存储就变成了存储一个文rbd0.object1.file。

5.6 Ceph RBD IO框架图

客户端写数据osd过程:

  1. 采用的是librbd的形式,使用librbd创建一个块设备,向这个块设备中写入数据。
  2. 在客户端本地同过调用librados接口,然后经过pool,rbd,object、pg进行层层映射,在PG这一层中,可以知道数据保存在哪3个OSD上,这3个OSD分为主从的关系。
  3. 客户端与primay OSD建立SOCKET 通信,将要写入的数据传给primary OSD,由primary OSD再将数据发送给其他replica OSD数据节点。

5.7 Ceph Pool和PG分布情况

说明:

  • pool是ceph存储数据时的逻辑分区,它起到namespace的作用。
  • 每个pool包含一定数量(可配置)的PG。
  • PG里的对象被映射到不同的Object上。
  • pool是分布到整个集群的。
  • pool可以做故障隔离域,根据不同的用户场景不一进行隔离。

5.8 Ceph 数据扩容PG分布

场景数据迁移流程:

  • 现状3个OSD, 4个PG
  • 扩容到4个OSD, 4个PG

现状:

扩容后:

说明:

        每个OSD上分布很多PG, 并且每个PG会自动散落在不同的OSD上。如果扩容那么相应的PG会进行迁移到新的OSD上,保证PG数量的均衡。

6 Ceph通信框架

6.1 Ceph通信框架种类介绍

        网络通信框架三种不同的实现方式:

  • Simple线程模式

        特点:每一个网络链接,都会创建两个线程,一个用于接收,一个用于发送。

        缺点:大量的链接会产生大量的线程,会消耗CPU资源,影响性能。

  • Async事件的I/O多路复用模式

        特点:这种是目前网络通信中广泛采用的方式。k版默认已经使用Asnyc了。

  • XIO方式使用了开源的网络通信库accelio来实现

        特点:这种方式需要依赖第三方的库accelio稳定性,目前处于试验阶段。

6.2 Ceph通信框架设计模式

        设计模式(Subscribe/Publish):

  • 订阅发布模式又名观察者模式,它意图是“定义对象间的一种一对多的依赖关系,
  • 当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。

6.3 Ceph通信框架流程图

步骤:

  1. Accepter监听peer的请求, 调用 SimpleMessenger::add_accept_pipe() 创建新的 Pipe 到 SimpleMessenger::pipes 来处理该请求。
  2. Pipe用于消息的读取和发送。该类主要有两个组件,Pipe::Reader,Pipe::Writer用来处理消息读取和发送。
  3. Messenger作为消息的发布者, 各个 Dispatcher 子类作为消息的订阅者, Messenger 收到消息之后, 通过 Pipe 读取消息,然后转给 Dispatcher 处理。
  4. Dispatcher是订阅者的基类,具体的订阅后端继承该类,初始化的时候通过 Messenger::add_dispatcher_tail/head 注册到 Messenger::dispatchers. 收到消息后,通知该类处理。
  5. DispatchQueue该类用来缓存收到的消息, 然后唤醒 DispatchQueue::dispatch_thread 线程找到后端的 Dispatch 处理消息。

6.4 Ceph通信框架类图

6.5 Ceph通信数据格式

        通信协议格式需要双方约定数据格式。消息的内容主要分为三部分:

  • header //消息头类型消息的信封
  • user data //需要发送的实际数据
  • payload //操作保存元数据
  • middle //预留字段
  • data //读写数据
  • footer //消息的结束标记

class Message : public RefCountedObject {

    protected:

        ceph_msg_header header; // 消息头

        ceph_msg_footer footer; // 消息尾

        bufferlist payload; // "front" unaligned blob

        bufferlist middle; // "middle" unaligned blob

        bufferlist data; // data payload (page-alignment will be preserved where possible)

        /* recv_stamp is set when the Messenger starts reading the Message off the wire */

        utime_t recv_stamp; //开始接收数据的时间戳

        /* dispatch_stamp is set when the Messenger starts calling dispatch() on its endpoints */

        utime_t dispatch_stamp; //dispatch 的时间戳

        /* throttle_stamp is the point at which we got throttle */

        utime_t throttle_stamp; //获取throttle 的slot的时间戳

        /* time at which message was fully read */

        utime_t recv_complete_stamp; //接收完成的时间戳

        ConnectionRef connection; //网络连接

        uint32_t magic = 0; //消息的魔术字

        bi::list_member_hook dispatch_q; //boost::intrusive 成员字段

};

struct ceph_msg_header {

        __le64 seq; // 当前session内 消息的唯一 序号

        __le64 tid; // 消息的全局唯一的 id

        __le16 type; // 消息类型

        __le16 priority; // 优先级

        __le16 version; // 版本号

        __le32 front_len; // payload 的长度

        __le32 middle_len;// middle 的长度

        __le32 data_len; // data 的 长度

        __le16 data_off; // 对象的数据偏移量

        struct ceph_entity_name src; //消息源

        /* oldest code we think can decode this. unknown if zero. */

        __le16 compat_version;

        __le16 reserved;

        __le32 crc; /* header crc32c */

} __attribute__ ((packed));

struct ceph_msg_footer {

        __le32 front_crc, middle_crc, data_crc; //crc校验码

        __le64 sig; //消息的64位signature

        __u8 flags; //结束标志

} __attribute__ ((packed));

7 Ceph CRUSH算法

7.1 数据分布算法挑战

数据分布和负载均衡:

        a. 数据分布均衡,使数据能均匀的分布到各个节点上。

        b. 负载均衡,使数据访问读写操作的负载在各个节点和磁盘的负载均衡。

灵活应对集群伸缩:

        a. 系统可以方便的增加或者删除节点设备,并且对节点失效进行处理。

        b. 增加或者删除节点设备后,能自动实现数据的均衡,并且尽可能少的迁移数据。

支持大规模集群:

        a. 要求数据分布算法维护的元数据相对较小,并且计算量不能太大。随着集群规模的增 加,数据分布算法开销相对比较小。

7.2 Ceph CRUSH算法说明

        CRUSH算法的全称为:Controlled Scalable Decentralized Placement of Replicated Data,可控的、可扩展的、分布式的副本数据放置算法。

        Ceph 分布数据的过程:首先计算数据 x 的 Hash 值并将结果和 PG 数目取余,以得到数据 x 对应的 PG 编号。然后,通过 CRUSH 算法将 PG 映射到一组 OSD 中。最后把数据 x 存放到 PG 对应的 OSD 中。注明:PG 全称是 Placement Group (放置组)。

        这个过程中包含了两次映射,第一次是数据 x 到 PG 的映射。如果把 PG 当作存储节点,那么传统 Hash 算法一样。不同的是, PG 是抽象的存储节点,它不会随着物理节点的加入或则离开而增加或减少,因此数据到 PG 的映射是稳定的。

         以 Dynamo 为例,在这个过程中, PG 起到了两个作用:第一个作用是划分数据分区。每个 PG 管理的数据区间相同,因而数据能够均匀地分布到 PG 上;第二个作用是充当 Dynamo 中 Token 的角色,即决定分区位置。实际上,这和 Dynamo 中固定分区数目,以及维持分区数目和虚拟节点数目相等的原则是同一回事。

        以 Ceph 为例, CRUSH 算法通过两次映射计算数据存储位置来确定如何存储和检索数据。CRUSH 使 Ceph 客户机能够直接与 OSDs 通信,而不是通过集中的服务器或代理。

        通过算法确定的数据存储和检索方法, Ceph 避免了单点故障、性能瓶颈和对其可伸缩性的物理限制。CRUSH 需要集群的映射,并使用 CRUSH 映射在 OSDs 中伪随机存储和检索数据,数据在集群中均匀分布。

7.3 Ceph CRUSH算法原理

CRUSH算法因子:

  • 层次化的Cluster Map

        反映了存储系统层级的物理拓扑结构。定义了OSD集群具有层级关系的静态拓扑结构。OSD层级使得CRUSH算法在选择OSD时实现了机架感知能力,也就是通过规则定义,使得副本可以分布在不同的机架、不同的机房中、提供数据的安全性。

  • Placement Rules

        决定了一个PG的对象副本如何选择的规则,通过这些可以自己设定规则,用户可以自定义设置副本在集群中的分布。

7.3.1 层级化的Cluster Map

        CRUSH Map是一个树形结构,OSDMap更多记录的是OSDMap的属性(epoch/fsid/pool信息以及osd的ip等等)。

         叶子节点是device(也就是osd),其他的节点称为bucket节点,这些bucket都是虚构的节点,可以根据物理结构进行抽象,当然树形结构只有一个最终的根节点称之为root节点,中间虚拟的bucket节点可以是数据中心抽象、机房抽象、机架抽象、主机抽象等。

7.3.2 数据分布策略Placement Rules

        数据分布策略Placement Rules主要有特点:

  1. 从CRUSH Map中的哪个节点开始查找
  2. 使用那个节点作为故障隔离域
  3. 定位副本的搜索模式(广度优先 or 深度优先)

rule replicated_ruleset #规则集的命名,创建pool时可以指定rule集

{

        ruleset 0 #rules集的编号,顺序编即可

        type replicated #定义pool类型为replicated(还有erasure模式)

        min_size 1 #pool中最小指定的副本数量不能小1

        max_size 10 #pool中最大指定的副本数量不能大于10

        step take default #查找bucket入口点,一般是root类型的bucket

        step chooseleaf firstn 0 type host #选择一个host,并递归选择叶子节点osd

        step emit #结束

}

7.3.3 Bucket随机算法类型

  • 一般的buckets:适合所有子节点权重相同,而且很少添加删除item。
  • list buckets:适用于集群扩展类型。增加item,产生最优的数据移动,查找item,时间复杂度O(n)。
  • tree buckets:查找负责度是O (log n), 添加删除叶子节点时,其他节点node_id不变。
  • straw buckets:允许所有项通过类似抽签的方式来与其他项公平“竞争”。定位副本时,bucket中的每一项都对应一个随机长度的straw,且拥有最长长度的straw会获得胜利(被选中),添加或者重新计算,子树之间的数据移动提供最优的解决方案。

7.4 CRUSH算法案例

说明:

        集群中有部分sas和ssd磁盘,现在有个业务线性能及可用性优先级高于其他业务线,能否让这个高优业务线的数据都存放在ssd磁盘上。

普通用户:

高优用户:

配置规则:

8 定制化Ceph RBD QOS

8.1 QOS介绍

        QoS (Quality of Service,服务质量)起源于网络技术,它用来解决网络延迟和阻塞等问题,能够为指定的网络通信提供更好的服务能力。

    问题:

        我们总的Ceph集群的iO能力是有限的,比如带宽、IOPS。如何避免用户争取资源,如果保证集群所有用户资源的高可用性,以及如何保证高优用户资源的可用性。所以我们需要把有限的IO能力合理分配。

8.2 Ceph IO操作类型

  • ClientOp:来自客户端的读写I/O请求。
  • SubOp:osd之间的I/O请求。主要包括由客户端I/O产生的副本间数据读写请求,以及由数据同步、数据扫描、负载均衡等引起的I/O请求。
  • SnapTrim:快照数据删除。从客户端发送快照删除命令后,删除相关元数据便直接返回,之后由后台线程删除真实的快照数据。通过控制snaptrim的速率间接控制删除速率。
  • Scrub:用于发现对象的静默数据错误,扫描元数据的Scrub和对象整体扫描的deep Scrub。
  • Recovery:数据恢复和迁移。集群扩/缩容、osd失效/从新加入等过程。

8.3 Ceph 官方QOS原理

        mClock是一种基于时间标签的I/O调度算法,最先被Vmware提出来的用于集中式管理的存储系统。(目前官方QOS模块属于半成品)。

基本思想:

  • reservation 预留,表示客户端获得的最低I/O资源。
  • weight 权重,表示客户端所占共享I/O资源的比重。
  • limit 上限,表示客户端可获得的最高I/O资源。

8.4 定制化QOS原理

8.4.1 令牌桶算法介绍

        基于令牌桶算法(TokenBucket)实现了一套简单有效的qos功能,满足了云平台用户的核心需求。

基本思想:

  • 按特定的速率向令牌桶投放令牌。
  • 根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送。
  • 符合匹配规则的报文,则需要令牌桶进行处理。当桶中有足够的令牌则报文可以被继续发送下去,同时令牌桶中的令牌量按报文的长度做相应的减少。
  • 当令牌桶中的令牌不足时,报文将不能被发送,只有等到桶中生成了新的令牌,报文才可以发送。这就可以限制报文的流量只能是小于等于令牌生成的速度,达到限制流量的目的。

8.4.2 RBD令牌桶算法流程

步骤:

  1. 用户发起请求异步IO到达Image中。
  2. 请求到达ImageRequestWQ队列中。
  3. 在ImageRequestWQ出队列的时候加入令牌桶算法TokenBucket。
  4. 通过令牌桶算法进行限速,然后发送给ImageRequest进行处理。

8.4.3 RBD令牌桶算法框架图

现有框架图:

令牌图算法框架图:

参考链接

Ceph的整体架构介绍,这篇文章带入Ceph的大门

Ceph介绍及原理架构分享 - 简书

分布式存储架构_百度百科

Ceph介绍(一):基本原理_Yannick_J的博客-CSDN博客_ceph

我所了解的各公司使用的 Ceph 存储集群 (携程、乐视、有云、宝德云、联通等) - SammyLiu - 博客园