0. 学会使用解析ceph的cluster map工具:node
ceph osd getcrushmap -o crush.map crushtool -d crush.map >> crush.txt
这时将一个ceph集群的 cluster map导入到crush.txt的文件中,这时能够cat这个文件看一下文件中保存了哪些内容,帮助理解下面的内容算法
1. 说明:这里首先要说明的是 一个object要保存三个副本,也就是要保存到三个osd上,当前的ceph集群能够存在N个osd节点,那么怎么来记录这个object保存到哪里了? 这里就要讲述这个伪随机的选择osd过程-----crush。 shell
pg 到OSD的映射的过程算法叫作crush 算法,这个算法是一个伪随机的过程,他能够从全部的OSD中,随机性选择一个OSD集合,可是同一个PG每次随机选择的结果是不变的,也就是映射的OSD集合是固定的。数组
2. crush 因子:工具
OSDMap管理当前ceph中全部的OSD,OSDMap规定了crush算法的一个范围,在这个范围中选择OSD结合。那么影响crush算法结果的有两种因素,一个就是OSDMap的结构,另一个就是crush rule。spa
OSDMap其实就是一个树形的结构,叶子节点是device(也就是osd),其余的节点称为bucket节点,这些bucket都是虚构的节点,能够根据物理结构进行抽象,固然树形结构只有一个最终的根节点称之为root节点,中间虚拟的bucket节点能够是数据中心抽象、机房抽象、机架抽象、主机抽象等如图。code
图1-4 osd组成的逻辑树形结构orm
上图中红色框内的节点都是bucket节点,这些节点都是根据实际状况进行抽象得来的。其实也就是实际中整个物理拓扑结构。这个拓扑里的每一个节点都有一个权重值,这个权重值等于全部子节点的权重之和,叶子节点的重量由osd的容量决定,通常设定1T的权重为1。这个权重值在crush算法中也有很重要的地位。递归
3.bucket类型解释:get
对于bucket节点不仅是虚设的节点,bucket一样有type。bucket的type有四种类型结构,uniform、list、tree、straw。这四种bucket有着不一样的特性,bucket的type设定一样也影响着crush算法。
3.1 uniform 类型:先来介绍下uniform bucket如何来定位数据在哪一个子节点的过程。
图1-5 uniform 定位子节点过程
先来讲明一下uniform的要素。bucket的全部子节点都保存在item[]数组之中。perm_x 是记录此次随机排布时 x的值,perm[]是在perm_x时候对item随机排列后的结果。r则是选择第几个副本。
定位子节点过程。这时咱们从新来看uniform定位子节点的过程。根据输入的x值判断是否为perm_x,若是不是,则须要从新排列perm[]数组,而且记录perm_x=x。若是x==perm_x时,这时算R = r%size,算后获得R,最后返回 perm[R]。
uniform bucket 适用的状况:
a.适用于全部子节点权重相同的状况。由于uniform的bucket在选择子节点时是不考虑权重的问题,所有随机选择。因此在权重上不会进行特别的照顾,为了公平起见最好是相同的权重节点。
b.适用于子节点变化几率小的状况。当子节点的数量进行变化时,size发生改变,在随机组合perm数组时,即便x相同,则perm数组须要彻底从新排列,也就意味着已经保存在子节点的数据要所有发生重排,形成不少数据的迁移。因此uniform不适合子节点变化的bucket,不然会产生大量已经保存的数据发生移动,全部的item上的数据均可能会发生相互之间的移动。
3.2 list 类型:list bucket的造成过程。list bucket 不是真的将全部的item都穿成一个链表,bucket的item仍然保存在item数组之中。这时的list bucket 每一个item 不只要保存的权重(根据容量换算而来)weight,还要记录前全部节点的重量之和sum_weight如图,list bucket的每一个item的权重能够不相同,也不须要按顺序排列。
图1-6 list bucket 造成过程
list bucket定位数据在子节点的方法。从head开始,会逐个的查找子节点是否保存数据。
如何判断当前子节点是否保存了数据呢?首先取了一个节点以后,根据x,r 和item的id 进行crush_hash获得一个w值。这个值与sum_weight之积,最后这个w再向右移16位,最后判断这个值与weight的大小,若是小于weight时,则选择当前的这个item,不然进行查找下一个item。
图1-7 list bucket 定位数据过程
list bucket使用的状况:
a.适用于集群拓展类型。当增长item时,会产生最优的数据移动。由于在list bucket中增长一个item节点时,都会增长到head部,这时其余节点的sum_weight都不会发生变化,只须要将old_head 上的sum_weight和weight之和添加到new_head的sum_weight就行了。这样时其余item之间不须要进行数据移动,其余的item上的数据 只须要和 head上比较就好,若是算的w值小于head的weight,则须要移动到head上,不然还保存在原来的item上。这样就得到了最优最少的数据移动。
b.list bucket存在一个缺点,就是在查找item节点时,只能顺序查找 时间复杂度为O(n)。
3.3 tree 类型:tree bucket 会借助一个叫作node_weight[ ]的数组来进行帮助搜索定位item。首先是node_weight[ ]的造成,nodeweight[ ]中不只包含了item,并且增长了不少中间节点,item都做为叶子节点。父节点的重量等于左右子节点的重量之和,递归到根节点以下图。
图1-8 tree bucket的造成过程
tree bucket的搜索过程,经过必定的方法造成node tree。这tree的查找从根节点开始直到找到叶子节点。当前节点的重量weight使用crush_hash(x,r)修正后,与左节点的重量left_weight比较,若是比左节点轻 则继续遍历左节点,不然遍历右节点以下图。因此该类型的bucket适合于查找的,对于变更的集群就没那么合适了。
图1-9 tree bucket选择过程
3.4 straw类型:这种类型是一种抽签类型的bucket,他选择子节点是公平的,straw和uniform的区别在于,straw算法考虑了子节点的权重,因此是最公平的bucket类型。
图 1-10 straw bucket的造成过程
straw bucket首先根据每一个节点的重量生成的straw,最后组成straw[] 数组。在straw定位副本的过程当中,每个定位都须要遍历全部的item,长度draw = crush(x,r,item_id)*straw[i]。找出那个最长的,最后选择这个最长,定位到副本。
4. crush rule介绍:
crush rule主要有3个重点:a.从OSDMap中的哪一个节点开始查找,b.使用那个节点做为故障隔离域,c.定位副本的搜索模式(广度优先 or 深度优先)。
# rules
rule replicated_ruleset #规则集的命名,建立pool时能够指定rule集
{
ruleset 0 #rules集的编号,顺序编便可
type replicated #定义pool类型为replicated(还有esurecode模式)
min_size 1 #pool中最小指定的副本数量不能小1\
max_size 10 #pool中最大指定的副本数量不能大于10
step take default #定义pg查找副本的入口点
step chooseleaf firstn 0 type host #选叶子节点、深度优先、隔离host
step emit #结束
}
5. 总结:
pg 选择osd的过程,首先要知道在rules中 指明从osdmap中哪一个节点开始查找,入口点默认为default也就是root节点,而后隔离域为host节点(也就是同一个host下面不能选择两个子节点)。由default到3个host的选择过程,这里由default根据节点的bucket类型选择下一个子节点,由子节点再根据自己的类型继续选择,知道选择到host,而后在host下选择一个osd。