Ceph 作为云厂商不可或缺的存储系统之一,有着优秀的性能、可靠性和可扩展性,是一种统一的、分布式的存储系统。但是,大家对 ceph 的技术原理有了解多少呢?本文主要从 ceph 概述、ceph 的系统结构、数据分配策略三方面对 ceph 作了详细的介绍。下来就跟随作者一起去看看 ceph 是如何工作的吧。
1 ceph 简述
什么是 ceph
Ceph 是一种为提高性能、可靠性和可扩展性而设计的统一的、分布式的存储系统。
“统一的”:意味着 Ceph 一套存储系统可以同时提供对象存储、块存储和文件系统存储三种功能,以便在满足不同应用需求的前提下简化部署和运维。
“分布式”:在 Ceph 系统中则意味着真正的无中心结构和没有理论上限的系统规模可扩展性。(在使用方面,各公司会有自己的考虑,做目前最大的 ceph 集群,影响 ceph 圈,引领 ceph 技术发展?求稳定,控制一定的规模等 )
ceph 的技术特征是什么
高可靠性。首先是针对存储在系统中的数据而言,通过多副本、纠删码方式尽可能保证数据不会丢失。其次,也包括数据写入过程中的可靠性,在用户将数据写入 Ceph 存储系统的过程中,通过强一致性写入,避免因为意外情况的出现造成数据丢失。
高度自动化。具体包括了数据的自动 failure detection 和自动 failure recovery。总体而言,这些自动化特性一方面保证了系统的高度可靠,一方面也保障了在系统规模扩大之后,其运维难度仍能保持在一个相对较低的水平。
高可扩展性。这里的“可扩展”概念比较广义,既包括了系统规模和存储容量的可扩展,也包括了随着系统节点数增加的聚合数据访问带宽的线性扩展,还包括了基于功能丰富强大的底层 API 提供多种功能、支持多种应用的功能性可扩展。
ceph 的技术这么优秀,那么有谁在用?
主要以云厂商为主(基本在用 OpenStack 的,后端存储都在用 ceph)
2 ceph 系统的层次结构
自下向上,可以将 Ceph 系统分为四个层次:
1.基础存储系统 RADOS(Reliable, Autonomic, Distributed Object Store,即可靠的、自动化的、分布式的对象存储)。
2.基础库 LIBRADOS 层。
3.高层应用接口层:包括了三个部分:RADOS GW(RADOS Gateway)、 RBD(Reliable Block Device)和 Ceph FS(Ceph File System)。
4.应用层。
Ceph 的底层是 RADOS 的组件:
一种是为数众多的、负责完成数据存储和维护功能的 OSD( Object Storage Device)。另一种则是若干个负责完成系统状态检测和维护的 Monitor。OSD 和 monitor 之间相互传输节点状态信息,共同得出系统的总体工作状态,并形成一个全局系统状态记录数据结构,即 cluster map(monmap osdmap pgmap)。这个数据结构与 RADOS 提供的特定算法相配合,便实现了 Ceph“无需查表,算算就好”的核心机制以及若干优秀特性。
1.OSD(Object Storage Device),可以被抽象为两个组成部分,即系统部分和守护进程(OSD deamon)部分。即一块磁盘(一些 CPU、一些内存),有一个 daemon 进程对它操作,进行数据存储和维护,是磁盘的“经纪人”,每个 osd 进程服务会监听一个端口,与其它 OSD 的 daemon、monitor、client 通信。
2.mon:monitor 检测和维护集群状态。每个 client 访问 OSD 都需要先访问 monitor 获取集群 map,从而知道需要和哪些 osd 节点通信。
3 数据分布策略 crush
Ceph 通过 crush 规则来控制数据的分布策略。
crush 规则具体解决了什么问题
1.控制把对象存入集群中,并随机均匀的分布在所有存储设备中。
2.老设备故障,新设备加入时支持数据的自动均衡迁移,并尽可能最小化数据迁移。
3.如何合理分布多副本数据到不同的设备,保证数据较高的可靠性。
两次映射完成数据的分布
Object -> PG -> OSD。
对象名 HASH -> pgid -> (osd1,osd2,osd3)。
1)File ——以 rbd 块存储为例,此处的 file 即为我创建了一个 rbd 块,假设我创建了 128M 的块,在创建块时候可以设定切分成多大的 object 存在存储设备上,默认是 4M,如下图:
2)Ojbect ——在 Ceph 中,一切皆对象,不论是视频,文本,照片等一切格式的数据,Ceph 统一将其看作是对象,不以它们的格式、大小来区分他们,只以对象名来区分,每个不同的对象都有不一样的对象名。
从 rados 层直接 put 一个对象到集群中:(原对象多大存入集群就多大)
从 rbd 应用接口层存数据到集群中:(对块做了切分,打散存入集群)
3)PG(Placement Group)—— PG 的用途是对 object 的存储进行组织和位置映射。具体而言,一个 PG 负责组织若干个 object(可以为数千个甚至更多),但一个 object 只能被映射到一个 PG 中,即 PG 和 object 之间是“一对多”映射关系。同时,一个 PG 会被映射到 n 个 OSD 上,而每个 OSD 上都会承载大量的 PG,即,PG 和 OSD 之间是“多对多”映射关系。在实践当中,n 至少为 2,如果用于生产环境,则至少为 3。一个 OSD 上的 PG 则可达到数百个。事实上,PG 数量的设置牵扯到数据分布的均匀性问题。
File -> object:从 rados 层直接存储,不对对象做任何处理,只以对象名为分区将对象存入集群,如果对象名重复则覆盖;从应用层,假设从 rbd 接口应用层存数据,可以在应用层设定统一切分对象大小,对象名为 block_name_prefix + ID ,存入后端存储设备。
Object -> PG 映射:要将不同的 object 映射到 PG 中去,这里采用了 HASH,hash(对象名)得到了一串十六进制随机数,并且对于一个同样的对象名,计算出来的结果永远都是一样的;用随机数除以 PG 的总数,求余,余数一定会落在 0 到 pg 总数减 1 之间;求余的好处就是对象数量规模越大,每个 PG 分布的对象数量就越平均,每个对象自有名字开始,他们要保存到的 PG 就已经可以计算确定了。计算公式:池 ID + hash(对象名) / pg_num -> pgid (注:故如果 pg_num 变化,会影响大量数据重新分布,假设 pg_num 从 16 调整为 32,那么该池将有约一半数据映射到新增的 pg 上)。
PG -> OSD 映射:算法的输出(即算法要达到什么效果):CRUSH 希望随机挑 OSD 出来,要满足权重越大的 OSD 被挑中的概率越大,为了达到随机的目的,它在挑之前让每个 OSD 都拿着自己的权重乘以一个随机数,再取乘积最大的那个,那么这样宏观来看,同样是乘以一个随机数,在样本容量足够大之后,这个随机数对挑中的结果不再有影响,起决定性影响的是 OSD 的权重,OSD 的权重(容量)越大,宏观来看被挑中的概率越大。如果我们想保存三个副本,那么只需要挑选 3 个 osd,把每个 PG 都映射到三个不同的 OSD 上即可。
我们有哪些输入
互不相同的 PG_ID、互不相同的 OSD_ID、OSD 的权重(根据 osd 对应的磁盘容量大小设置)。这里我直接使用 CRUSH 里面采取的 Straw 算法,翻译过来就是抽签算法,Crush 算法的过程(有人将该过程形象的描述为把这些 OSD 搓一搓,选择一个最长的签):
1.CRUSH_HASH( PG_ID, OSD_ID, r ) ===> draw (搓一搓,得到一个随机数,r 可认为是常量)。
2.( draw &0xffff ) osd_weight ===> osd_straw (随机数 osd 权重)。
3.pick up high_osd_straw 。(挑选乘积最大的 osd)
4.多次抽签。( r+1 继续下次抽签,如果挑选的 osd 重复,则 r 继续+1 继续抽签,直到选够副本个数个 osd )
关键的随机数, CRUSH 希望得到这样一个随机数有什么要求?
该随机数和 PG_ID 有关、与 OSD_ID 有关,当相同的输入时,计算得出的输出值一定是相同的,并且有一定随机性。(输出是定值,保证了在集群池中的 PG 不变,没有扩缩容增减 osd,没有调整 osd 权重的时候,集群的数据分布永远是不变的)
pg 到 osd 的映射过程
1.给出一个 PG_ID,作为 CRUSH_HASH 的输入。
2.CRUSH_HASH(PG_ID, OSD_ID, r) 得出一个随机数。
3.对于所有的 OSD 用他们的权重乘以每个 OSD_ID 对应的随机数,得到乘积。
4.选出乘积最大的 OSD,这个 PG 就会保存到这个 OSD 上。
5.我们把 r+1,再求一遍随机数,重复上述过程,选出乘积最大的 OSD,如果和之前的 OSD 编号不一样,那么就选中它;如果和之前的 OSD 编号一样的话,那么再把 r+2,再选一次,直到选出我们需要的三个不一样编号的 OSD 为止。
Pg 到 osd 的映射过程如果就这样完成了,怎么解决故障阈的问题?怎么人为定义我想把数据分布在哪个机柜?
定义一个树形结构,该树形结构中 osd 之外的节点我们称为 bucket;每个 OSD 有 weight,每个主机也可以有一个 weight,这个 weight 由主机内的所有 OSD 的 weight 累加而得;每个 rack 的 weight 由所有主机的 weight 累加而得;root 的 weight 其实就是 rack 的权重之和;同样 bucket 也有 ID;仿照 CRUSH 选 OSD 的方法来选择 bucket,并且还可以定义从树形结构的根节点每次从下层节点选择多少个 bucket。
4 集群维护
理解了 crush 算法的原理,其实 ceph 的集群维护就是维护集群的 crush 规则。( 即 PG_ID/BUCKET_ID/OSD_ID/权重控制 PG 的映射关系)
1.新增/删除 OSD(扩缩容) 首先根据配置信息与 monitor 通信,monitor 将其加入 cluster map,并设置为 up 或 out 状态,权重生效;删除 osd 过程相反。
2.自动化的故障恢复(Failure recovery) 收到 monitor 发过来的 cluster map 之后,这个新 OSD 计算出自己所承载的 PG 以及和自己承载同一个 PG 的其他 OSD。然后与这些 OSD 取得联系。如果这个 PG 目前处于降级状态(即承载该 PG 的 OSD 个数少于正常值),则其他 OSD 将把这个 PG 内的所有对象和元数据赋值给新 OSD。数据复制完成后,新 OSD 被置为 up 且 in 状态,cluster map 更新。
本文转载自公众号 360 云计算(ID:hulktalk)。
原文链接:
https://mp.weixin.qq.com/s/KBaagb1zrkAmLyVgmkzJ3A
评论