江中散人

V1

2022/09/21阅读:12主题:默认主题

ceph

 《重识云原生系列》专题索引:

  1. 第一章——不谋全局不足以谋一域
  2. 第二章计算第1节——计算虚拟化技术总述
  3. 第二章计算第2节——主流虚拟化技术之VMare ESXi
  4. 第二章计算第3节——主流虚拟化技术之Xen
  5. 第二章计算第4节——主流虚拟化技术之KVM
  6. 第二章计算第5节——商用云主机方案
  7. 第二章计算第6节——裸金属方案
  8. 第三章云存储第1节——分布式云存储总述
  9. 第三章云存储第2节——SPDK方案综述
  10. 第三章云存储第3节——Ceph统一存储方案
  11. 第三章云存储第4节——OpenStack Swift 对象存储方案
  12. 第三章云存储第5节——商用分布式云存储方案
  13. 第四章云网络第一节——云网络技术发展简述
  14. 第四章云网络4.2节——相关基础知识准备
  15. 第四章云网络4.3节——重要网络协议
  16. 第四章云网络4.3.1节——路由技术简述
  17. 第四章云网络4.3.2节——VLAN技术
  18. 第四章云网络4.3.3节——RIP协议
  19. 第四章云网络4.3.4节——OSPF协议

        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 需要集群的映射,并使�

分类:

后端

标签:

云计算

作者介绍

江中散人
V1