openstack-notes

ceph-deploy时可以指定内网和外网两个网段

第一部分

1 Ceph简介

Ceph是一个统一的分布式存储系统,设计初衷是提供较好的性能、可靠性和可扩展性。它是一个统一的存储系统,既支持传统的块、文件存储协议,例如SAN和NAS,也支持新兴的对象存储协议,如S3和Swift,这使得Ceph理论上可以满足时下一切主流的存储应用的要求。

Ceph项目最早起源于Sage就读博士期间的工作(最早的成果于2004年发表),并随后贡献给开源社区。在经过了数年的发展之后,目前已得到众多云计算厂商的支持并被广泛应用。RedHat及OpenStack都可与Ceph整合以支持虚拟机镜像的后端存储。

高可用性

高可扩展性

特性丰富

a. 支持三种存储接口:块存储、文件存储、对象存储。

b. 支持自定义接口,支持多种语言驱动。

特点:

支持三种接口

640?wx_fmt=png

基于 RADOS 的 Ceph 对象存储集群包括两类守护进程:对象存储守护进程( OSD )把存储节点上的数据存储为对象; Ceph 监视器( MON )维护集群运行图的主拷贝。一个 Ceph 集群可以包含数千个存储节点,最简系统至少需要一个监视器和两个 OSD 才能做到数据复制。

1.1 Ceph架构

image-20201231160559413

系统架构。 客户端通过直接与OSD通信来执行文件I / O。 每个进程可以直接链接到客户端实例,也可以与已安装的文件系统进行交互。

1.2 ceph读写流程

Read:

Write:

1.3 三种存储方式

1. 块设备

典型设备: 磁盘阵列,硬盘

主要是将裸磁盘空间映射给主机使用的。

优点:

缺点:

使用场景:

2.文件存储

典型设备: FTP、NFS服务器
为了克服块存储文件无法共享的问题,所以有了文件存储。
在服务器上架设FTP与NFS服务,就是文件存储。

优点:

缺点:

使用场景:

3.对象存储

img

典型设备: 内置大容量硬盘的分布式服务器(swift, s3)
多台服务器内置大容量硬盘,安装上对象存储管理软件,对外提供读写访问功能。

优点:

使用场景: (适合更新变动较少的数据)

###


2 Ceph I/O流程和数据分布

img

img

步骤:

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

2.1 新主I/O流程图

img

步骤:

  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变成副本。

2.2 Ceph I/O算法流程

img

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

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

  3. b. ono(File切分产生的某个object的序号,默认以4M切分一个块大小)。
  4. c. oid(object id: ino + ono)。

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

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

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

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

  9. a. CRUSH(pgid)->(osd1,osd2,osd3) 。
locator = object_name
obj_hash =  hash(locator)
pg = obj_hash % num_pg
osds_for_pg = crush(pg)  # returns a list of osds
primary = osds_for_pg[0]
replicas = osds_for_pg[1:]Copy

2.3 Ceph RBD IO流程

img

  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。

img

客户端写数据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数据节点。

2.4 Ceph Pool和PG分布情况

img

2.5 Ceph 数据扩容PG分布

场景数据迁移流程:

扩容前

img

扩容后

img

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

image-20210105203533111

上图:在将写入应用于复制对象的所有OSD上的缓冲区高速缓存后,RADOS会以ack响应。 只有在将其安全地提交到磁盘之后,才将最终提交通知发送到客户端。这确保了数据的安全性。

主服务器将更新转发到副本,并在将更新应用到所有OSD的内存缓冲区高速缓存后回复确认,从而允许客户端上的同步POSIX调用返回。 当数据安全地提交到磁盘时,将发送一次最终提交(可能在几秒钟后)。 仅在完全复制更新日期之后,我们才会将确认发送给客户端,以无缝地容忍任何单个OSD的故障,即使这样做会增加客户端的延迟。 默认情况下,客户端还会缓冲写入操作,直到它们承诺避免在放置组中所有OSD同时掉电的情况下避免数据丢失为止。 在这种情况下进行恢复时,RADOS允许在接受新的更新之前,以固定的间隔重播先前已确认(因此有序)的更新。

详细请见PG读写及迁移


3 Ceph心跳机制

心跳是用于节点间检测对方是否故障的,以便及时发现故障节点进入相应的故障处理流程。

问题:

故障检测策略应该能够做到:

心跳检测

img

OSD节点会监听public、cluster、front和back四个端口

Ceph OSD之间相互心跳检测

img

Ceph OSD与Mon心跳检测

img

OSD报告给Monitor:

Monitor统计下线OSD

Ceph心跳检测总结

Ceph通过伙伴OSD汇报失效节点和Monitor统计来自OSD的心跳两种方式判定OSD节点失效。

4 Ceph通信框架

Simple线程模式

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

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

Ceph通信框架设计模式

设计模式(Subscribe/Publish)

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

img

Accepter监听peer的请求, 调用 SimpleMessenger::add_accept_pipe() 创建新的 Pipe 到 SimpleMessenger::pipes 来处理该请求。

Pipe用于消息的读取和发送。该类主要有两个组件,Pipe::Reader,Pipe::Writer用来处理消息读取和发送。

Messenger作为消息的发布者, 各个 Dispatcher 子类作为消息的订阅者, Messenger 收到消息之后, 通过 Pipe 读取消息,然后转给 Dispatcher 处理。

Dispatcher调度员是订阅者的基类,具体的订阅后端继承该类,初始化的时候通过 Messenger::add_dispatcher_tail/head 注册到 Messenger::dispatchers. 收到消息后,通知该类处理。

DispatchQueue该类用来缓存收到的消息, 然后唤醒 DispatchQueue::dispatch_thread 线程找到后端的 Dispatch 处理消息。

img

通信类框架图

img

通信数据格式

通信协议格式需要双方约定数据格式。

消息的内容主要分为三部分:

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));Copy

5 Ceph CRUSH算法

Controlled Replication Under Scalable Hashing, 可扩展哈希下的可控复制。以数据唯一标识符、当前存储集群的拓扑结构以及数据备份策略作为CRUSH输入,可以随时随地的通过计算获取数控所在的底层存储设备的位置并直接与其通信,从而避免查表操作,实现去中心化和高度并发。

CRUSH是一种伪随机算法,采用一致性哈希

OSD MAP: 包含当前所有pool的状态,和所有OSD状态。

CRUSH MAP: 包含当前磁盘、服务器、机架的层次结构。

CRUSH Rules:数据映射的策略。以便灵活放置Object。

数据分布算法挑战

数据分布和负载均衡

灵活应对集群伸缩

支持大规模集群

Ceph CRUSH算法原理

CRUSH算法因子:

下表展示了Cluster Map一些常见节点的层级

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

数据分布策略Placement Rules

在完成了使用clustermap建立对应的集群的拓扑结构描述后,可以定义placement rule 来完成数据映射.

这些操作有三种类型:

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

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        #结束
}Copy

CRUSH算法案例

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

普通用户:

img

高优用户

img

配置规则

作者:img

限于篇幅,我们对CRUSH的介绍十分简略,更详细的请看A First Galance At Crush一文.


6 定制化Ceph RBD QOS

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

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

Ceph IO操作类型

详细请见Ceph QoS策略

参考资料

https://www.jianshu.com/p/cc3ece850433


  1. Weil S A Brandt S A , Miller E L , et al. CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data[C]// IEEE Sc Conference. ACM, 2006.
  2. Weil S A, Brandt S A, Miller E L, et al. Ceph: A scalable, high-performance distributed file system[C]//Proceedings of the 7th symposium on Operating systems design and implementation. 2006: 307-320.