Ceph作为云厂商不可或缺的存储系统之一,有着优秀的性能、可靠性和可扩展性,是一种统一的、分布式的存储系统。但是,大家对ceph的技术原理有了解多少呢?本文主要从ceph概述、ceph的系统结构、数据分配策略三方面对ceph作了详细的介绍。下来就跟随作者一起去看看ceph是如何工作的吧。

PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!

ceph基本架构及数据分布原理_Java


1

ceph简述

什么是ceph

Ceph是一种为提高性能、可靠性和可扩展性而设计的统一的、分布式的存储系统。“统一的”:意味着Ceph一套存储系统可以同时提供对象存储、块存储和文件系统存储三种功能,以便在满足不同应用需求的前提下简化部署和运维。“分布式”:在Ceph系统中则意味着真正的无中心结构和没有理论上限的系统规模可扩展性。(在使用方面,各公司会有自己的考虑,做目前最大的ceph集群,影响ceph圈,引领ceph技术发展?求稳定,控制一定的规模等 )

ceph的技术特征是什么

高可靠性。首先是针对存储在系统中的数据而言,通过多副本、纠删码方式尽可能保证数据不会丢失。其次,也包括数据写入过程中的可靠性,在用户将数据写入Ceph存储系统的过程中,通过强一致性写入,避免因为意外情况的出现造成数据丢失。高度自动化。具体包括了数据的自动failure detection和自动failure recovery。总体而言,这些自动化特性一方面保证了系统的高度可靠,一方面也保障了在系统规模扩大之后,其运维难度仍能保持在一个相对较低的水平。高可扩展性。这里的“可扩展”概念比较广义,既包括了系统规模和存储容量的可扩展,也包括了随着系统节点数增加的聚合数据访问带宽的线性扩展,还包括了基于功能丰富强大的底层API提供多种功能、支持多种应用的功能性可扩展。ceph的技术这么优秀,那么有谁在用?
主要以云厂商为主(基本在用OpenStack的,后端存储都在用ceph)ceph基本架构及数据分布原理_Java_02


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. 应用层。

  1. ceph基本架构及数据分布原理_Java_03
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)。
ceph基本架构及数据分布原理_Java_04

1)File ——以rbd块存储为例,此处的file即为我创建了一个rbd块,假设我创建了128M的块,在创建块时候可以设定切分成多大的object存在存储设备上,默认是4M,如下图:


ceph基本架构及数据分布原理_Java_05

2)Ojbect ——在Ceph中,一切皆对象,不论是视频,文本,照片等一切格式的数据,Ceph统一将其看作是对象,不以它们的格式、大小来区分他们,只以对象名来区分,每个不同的对象都有不一样的对象名。从rados层直接put一个对象到集群中:(原对象多大存入集群就多大)
ceph基本架构及数据分布原理_Java_06

从rbd应用接口层存数据到集群中:(对块做了切分,打散存入集群)

ceph基本架构及数据分布原理_Java_07

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数量的设置牵扯到数据分布的均匀性问题。

ceph基本架构及数据分布原理_Java_08

  • 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更新。