2003年加州大学Santa Cruz分校的Sage Weil专为博士论文设计的新一代*软件分布式文件系统,并于2012年4月,Sage Weil成立了Inktank公司
2010年3月之后的linux内核中,嵌入了ceph
2014年4月30日,RedHat以$175million的价格收购了Inktank
在目前开源世界里多样的存储项目中,不同的项目都有侧重点,而它们最终都是要为企业的IT基础设施服务。那么企业IT基础设施经理们到底需要怎么样的存储,它们的需求得到满足了吗?
从上图我们可以了解到存储接口需求、扩展、运维和成本构成了企业级存储产品的四大中心。几乎所有的存储产品包括硬件(存储一体机,SAN)和软件都致力于在这个方面强调自己的优势,它们或者考虑成本,或者强调扩展性。那么我们来看Ceph它是如何定位自己的。
1. 架构
Ceph是统一存储系统,支持三种接口:
Object:有原生的API,而且也兼容Swift和S3的API
Block:支持精简配置、快照、克隆
File:Posix接口,支持快照
Ceph也是分布式存储系统,它的特点如下:
高扩展性:使用普通x86服务器,支持10~1000台服务器,支持TP到PB级的扩展
高可靠性:没有单点故障,多数据副本,自动管理,自动修复
高性能:数据分布均衡,并行化高,对于objects storage和block storage,不需要元数据服务器
Ceph模块架构图:
底层是Rados,也是Ceph实现分布式存储的根本,所有存储接口都是基于Rados实现的。Rados本身就是一个对象存储接口,它自身维护了一个集群状态和实现了数据分发的要求,我们通常也讲Rados称为Ceph Cluster,因为其上的存储接口如CephFS都是基于其上的接口实现而已
RADOS的组件(A reliable, autonomous, distributed object storage):
OSD: 每一个disk、SSD或者RAID group或者其他一个物理存储设备都成为一个OSD,主要负责存储和查找对象,并且负责向该对象的复制节点分发和恢复。
Monitor: 维护集群的成员和状态,维护整个ceph集群的全局状态。提供强一致性的决策(类似于Zookeeper的作用)
RADOS具有很强的扩展性和可编程性,Ceph基于RADOS开发了Object Storage、Block Storage、FileSystem。Ceph另外两个组件是:
MDS:用于保存CephFS的元数据。
RADOS Gateway:对外提供REST接口,兼容S3和Swift的API。
在传统架构中,客户谈论到一个集中的组件(如网关,代理,API等),作为单点进入到一个复杂的子系统。这会带来性能和可扩展性的限制,同时引入单点故障(即,如果集中的组件出现故障,整个系统也出现故障)。
Ceph的消除了集中式网关,使客户能够直接与Ceph的OSD守护进程进行互动。Ceph的OSD守护进程创建对象的副本,在其他Ceph的节点上,以确保数据的安全性和的高可用性。Ceph的还采用了集群监视器,以确保高可用性。为了消除集中Ceph的使用这种算法叫做CRUSH。
RADOS分发策略�CCRUSH算法:
Ceph的客户端和Ceph的OSD守护进程都使用CRUSH算法来高效地对数据容器的信息需求进行计算,而不必依赖于一个查找表。CRUSH与旧方法相比,提供了更好的数据管理机制,使大规模清晰地将工作分配到集群中的所有客户端和OSD守护。CRUSH使用智能的数据复制,以确保弹性,这样可以更好的适合于超大规模存储。以下各节提供更多的细节CRUSH是如何工作的。
从上图的流程解读RADOS是如何将对象分发到不同的OSD上(OSD),首先需要了解Ceph定义的几个存储区域概念。
Pool是一个命名空间,客户端向RADOS上存储对象时需要指定一个Pool,Pool通过配置文件定义并可以指定Pool的存储OSD节点范围和PG数量。
PG是Pool内部的概念,是对象和OSD的中间逻辑分层,对象首先会通过简单的Hash算法来得到其存储的PG,这个PG和对象是确定的。然后每一个PG都有一个primary OSD和几个Secondary OSD,对象会被分发都这些OSD上存储,而这个分发策略称为CRUSH―Ceph的数据均匀分布的核心。
需要注意的是整个CRUSH以上的流程实现都是在客户端计算,因此客户端本身需要保存一份Cluster Map,而这是从Monitor处获得。从这里我们也可以了解到Monitor主要职责就是负责维护这份Cluster Map并保证强一致性。
CRUSH通过伪随机算法来确保均匀的数据分布,它的输入是PG,Cluster State和Policy,并且保证CRUSH的Object Name一样的情况下,即使后两者参数发生改变也会得到一致的读取(注意是读取)。并且这个CRUSH算法是可配置的,通过PG Number和Weight的指定可以得到不同的分布策略。这个可配置的分布策略让Ceph的能力得到极大加强。
RADOS的逻辑结构:
在使用RADOS系统时,大量的客户端程序通过与OSD或者monitor的交互获取cluster map,然后直接在本地进行计算,得出对象的存储位置后,便直接与对应的OSD通信,完成数据的各种操作。可见,在此过程中,只要保证cluster map不频繁更新,则客户端显然可以不依赖于任何元数据服务器,不进行任何查表操作,便完成数据访问流程。在RADOS的运行过程中,cluster map的更新完全取决于系统的状态变化,而导致这一变化的常见事件只有两种:OSD出现故障,或者RADOS规模扩大。而正常应用场景下,这两种事件发生 的频率显然远远低于客户端对数据进行访问的频率。
群集映射:
Ceph的使用取决于Ceph的客户和Ceph的OSD守护集群拓扑知识,包括5类映射
1.监控映射:
包含集群FSID,位置,名称地址和每个监视器的端口。这也表明现在的时期里,当创建映射时,并且它最后一被改变。要查看监控映射,执行如下命令
# ceph mon dump
2.OSD映射:
包含集群FSID,当创建和最后修改映射时间,池的列表,副本大小,PG数字的OSD的列表,他们的状态(例如,up,in)。要查看一个OSD映射,执行如下命令
# ceph osd dump
3.PG映射:
包含PG版本,其时间戳记,最后OSD映射时代,完整的比率,如PG ID,每个配置组集,代理设置,在PG的状态(例如 active + clean)和每个池数据使用统计数据。
4.CRUSH映射
包含存储设备,故障域层次结构(例如,设备,主机,机架,行,空间等),并遍历层次结构存储数据时的规则的列表。要查看CRUSH映射,执行命令: getcrushmap �Co {filename},然后通过执行crushtool -D {comp-crushmap-filename} -O {decomp-crushmap-filename}反编译。你可以查看在文本编辑器或反编译的映射或使用命令cat查看。
5.MDS映射
包含了现有的MDS映射从它创建至最后一次修改的时期。它还包含池用于存储元数据,元数据服务器的列表,以及元数据服务器中。要查看MDS映射,执行如下命令
# ceph mds dump
每个映射保持一个重复历史关于其运行状态的变化。Ceph的监视器保持集群的主副本映射,包括集群成员的状态,变化,和Ceph的存储集群的整体健康。
上图左侧的几个概念说明如下:
1. File ―― 此处的file就是用户需要存储或者访问的文件。对于一个基于Ceph开发的对象存储应用而言,这个file也就对应于应用中的“对象”,也就是用户直接操作的“对象”。
2. Ojbect ―― 此处的object是RADOS所看到的“对象”。Object与上面提到的file的区别是,object的最大size由RADOS限定(通常为2MB或4MB),以便实现底层存储的组织管理。因此,当上层应用向RADOS存入size很大的file时,需要将file切分成统一大小的一系列object(最后一个的大小可以不同)进行存储。为避免混淆,在本文中将尽量避免使用中文的“对象”这一名词,而直接使用file或object进行说明。
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数量的设置牵扯到数据分布的均匀性问题。关于这一点,下文还将有所展开。
4. OSD ―― 即object storage device,前文已经详细介绍,此处不再展开。唯一需要说明的是,OSD的数量事实上也关系到系统的数据分布均匀性,因此其数量不应太少。在实践当中,至少也应该是数十上百个的量级才有助于Ceph系统的设计发挥其应有的优势。
基于上述定义,便可以对寻址流程进行解释了。具体而言, Ceph中的寻址至少要经历以下三次映射:
File -> Object映射:
ino(File的元数据,File的唯一id)
ono(File切分产生的某个object的序号)
oid(object id: ino + ono)
这次映射的目的是,将用户要操作的file,映射为RADOS能够处理的object。其映射十分简单,本质上就是按照object的最大size对file进行切分,相当于RAID中的条带化过程。这种切分的好处有二:一是让大小不限的file变成最大size一致、可以被RADOS高效管理的object;二是让对单一file实施的串行处理变为对多个object实施的并行化处理。
每一个切分后产生的object将获得唯一的oid,即object id。其产生方式也是线性映射,极其简单。图中,ino是待操作file的元数据,可以简单理解为该file的唯一id。ono则是由该file切分产生的某个object的序号。而oid就是将这个序号简单连缀在该file id之后得到的。举例而言,如果一个id为filename的file被切分成了三个object,则其object序号依次为0、1和2,而最终得到的oid就依次为filename0、filename1和filename2。
这里隐含的问题是,ino的唯一性必须得到保证,否则后续映射无法正确进行。
Object -> PG映射:
hash(oid)&mask -> pgid
mask = PG总数m(m为2的整数幂)- 1
Ceph指定一个静态hash函数计算oid的值,将oid映射成一个近似均匀分布的伪随机值,然后和mask按位相与,得到pgid。
首先是使用Ceph系统指定的一个静态哈希函数计算oid的哈希值,将oid映射成为一个近似均匀分布的伪随机值。然后,将这个伪随机值和mask按位相与,得到最终的PG序号(pgid)。根据RADOS的设计,给定PG的总数为m(m应该为2的整数幂),则mask的值为m-1。因此,哈希值计算和按位与操作的整体结果事实上是从所有m个PG中近似均匀地随机选择一个。基于这一机制,当有大量object和大量PG时,RADOS能够保证object和PG之间的近似均匀映射。又因为object是由file切分而来,大部分object的size相同,因而,这一映射最终保证了,各个PG中存储的object的总数据量近似均匀。
从介绍不难看出,这里反复强调了“大量”。只有当object和PG的数量较多时,这种伪随机关系的近似均匀性才能成立,Ceph的数据存储均匀性才有保证。为保证“大量”的成立,一方面,object的最大size应该被合理配置,以使得同样数量的file能够被切分成更多的object;另一方面,Ceph也推荐PG总数应该为OSD总数的数百倍,以保证有足够数量的PG可供映射。
PG -> OSD映射:
采用CRUSH算法,将pgid代入其中,然后得到一组共n个OSD(n由部署配置文件决定,一般3个)
第三次映射就是将作为object的逻辑组织单元的PG映射到数据的实际存储单元OSD。如图所示,RADOS采用一个名为CRUSH的算法,将pgid代入其中,然后得到一组共n个OSD。这n个OSD即共同负责存储和维护一个PG中的所有object。前已述及,n的数值可以根据实际应用中对于可靠性的需求而配置,在生产环境下通常为3。具体到每个OSD,则由其上运行的OSD deamon负责执行映射到本地的object在本地文件系统中的存储、访问、元数据维护等操作。
和“object -> PG”映射中采用的哈希算法不同,这个CRUSH算法的结果不是绝对不变的,而是受到其他因素的影响。其影响因素主要有二:
一、是当前系统状态,也就是上文逻辑结构中曾经提及的cluster map。当系统中的OSD状态、数量发生变化时,cluster map可能发生变化,而这种变化将会影响到PG与OSD之间的映射。
二、是存储策略配置。这里的策略主要与安全相关。利用策略配置,系统管理员可以指定承载同一个PG的3个OSD分别位于数据中心的不同服务器乃至机架上,从而进一步改善存储的可靠性。
因此,只有在系统状态(cluster map)和存储策略都不发生变化的时候,PG和OSD之间的映射关系才是固定不变的。在实际使用当中,策略一经配置通常不会改变。而系统状态的改变或者是由于设备损坏,或者是因为存储集群规模扩大。好在Ceph本身提供了对于这种变化的自动化支持,因而,即便PG与OSD之间的映射关系发生了变化,也并不会对应用造成困扰。事实上,Ceph正是需要有目的的利用这种动态映射关系。正是利用了CRUSH的动态特性,Ceph可以将一个PG根据需要动态迁移到不同的OSD组合上,从而自动化地实现高可靠性、数据分布re-blancing等特性。
之所以在此次映射中使用CRUSH算法,而不是其他哈希算法,原因之一正是CRUSH具有上述可配置特性,可以根据管理员的配置参数决定OSD的物理位置映射策略;另一方面是因为CRUSH具有特殊的“稳定性”,也即,当系统中加入新的OSD,导致系统规模增大时,大部分PG与OSD之间的映射关系不会发生改变,只有少部分PG的映射关系会发生变化并引发数据迁移。这种可配置性和稳定性都不是普通哈希算法所能提供的。因此,CRUSH算法的设计也是Ceph的核心内容之一。
Ceph通过三次映射,完成了从file到object、PG和OSD整个映射过程。通观整个过程,可以看到,这里没有任何的全局性查表操作需求。至于唯一的全局性数据结构cluster map,在后文中将加以介绍。可以在这里指明的是,cluster map的维护和操作都是轻量级的,不会对系统的可扩展性、性能等因素造成不良影响。
集群的维护:
若干个mintor共同负责ceph集群中所有osd状态的发现与记录,并共同形成cluster map的master版本,然后扩散至全体osd和client。Osd使用cluster map进行数据维护,而client使用cluster map进行数据寻址。
在集群中,各个monitor的功能总体上是一样的,其相互间的关系可以被简单理解为主从备份关系。因此,在下面的讨论中不对各个monitor加以区分。
monitor并不主动轮询各个OSD的当前状态。正相反,OSD需要向monitor上报状态信息。常见的上报有两种情况:一是新的OSD被加入集群,二是某个OSD发现自身或者其他OSD发生异常。在收到这些上报信息后,monitor将更新cluster map信息并加以扩散。
Cluster map实际内容:
1、Epoch版本号。Cluster map的epoch是一个单调递增序列。Epoch越大,则cluster map版本越新。因此,持有不同版本cluster map的OSD或client可以简单地通过比较epoch决定应该遵从谁手中的版本。而monitor手中必定有epoch最大、版本最新的cluster map。当任意两方在通信时发现彼此epoch值不同时,将默认先将cluster map同步至高版本一方的状态,再进行后续操作。
2、各个OSD的网络地址。
3、各个OSD的状态。OSD状态的描述分为两个维度:up或者down(表明OSD是否正常工作),in或者out(表明OSD是否在至少一个PG中)。因此,对于任意一个OSD,共有四种可能的状态:
―― Up且in:说明该OSD正常运行,且已经承载至少一个PG的数据。这是一个OSD的标准工作状态;
―― Up且out:说明该OSD正常运行,但并未承载任何PG,其中也没有数据。一个新的OSD刚刚被加入Ceph集群后,便会处于这一状态。而一个出现故障的OSD被修复后,重新加入Ceph集群时,也是处于这一状态;
―― Down且in:说明该OSD发生异常,但仍然承载着至少一个PG,其中仍然存储着数据。这种状态下的OSD刚刚被发现存在异常,可能仍能恢复正常,也可能会彻底无法工作;
―― Down且out:说明该OSD已经彻底发生故障,且已经不再承载任何PG。
4、CRUSH算法配置参数。表明了Ceph集群的物理层级关系(cluster hierarchy),位置映射规则(placement rules)。
Client从Monitors中得到CRUSH MAP、OSD MAP、CRUSH Ruleset,然后使用CRUSH算法计算出Object所在的OSD set。所以Ceph不需要Name服务器,Client直接和OSD进行通信。伪代码如下所示:
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:]
这种数据映射的优点是:
把Object分成组,这降低了需要追踪和处理metadata的数量(在全局的层面上,我们不需要追踪和处理每个object的metadata和placement,只需要管理PG的metadata就可以了。PG的数量级远远低于object的数量级)。
增加PG的数量可以均衡每个OSD的负载,提高并行度。
分隔故障域,提高数据的可靠性。
数据操作流程,强一致性:
当某个client需要向Ceph集群写入一个file时,首先需要在本地完成5.1节中所叙述的寻址流程,将file变为一个object,然后找出存储该object的一组三个OSD。这三个OSD具有各自不同的序号,序号最靠前的那个OSD就是这一组中的Primary OSD,而后两个则依次是Secondary OSD和Tertiary OSD。
找出三个OSD后,client将直接和Primary OSD通信,发起写入操作(步骤1)。Primary OSD收到请求后,分别向Secondary OSD和Tertiary OSD发起写入操作(步骤2、3)。当Secondary OSD和Tertiary OSD各自完成写入操作后,将分别向Primary OSD发送确认信息(步骤4、5)。当Primary OSD确信其他两个OSD的写入完成后,则自己也完成数据写入,并向client确认object写入操作完成(步骤6)。
之所以采用这样的写入流程,本质上是为了保证写入过程中的可靠性,尽可能避免造成数据丢失。同时,由于client只需要向Primary OSD发送数据,因此,在Internet使用场景下的外网带宽和整体访问延迟又得到了一定程度的优化。
高新能:
Client和Server直接通信,不需要代理和转发
多个OSD带来的高并发度。objects是分布在所有OSD上。
负载均衡。每个OSD都有权重值(现在以容量为权重)。
client不需要负责副本的复制(由primary负责),这降低了client的网络消耗。
高可靠性:
数据多副本。可配置的per-pool副本策略和故障域布局,支持强一致性。
没有单点故障。可以忍受许多种故障场景;防止脑裂;单个组件可以滚动升级并在线替换。
所有故障的检测和自动恢复。恢复不需要人工介入,在恢复期间,可以保持正常的数据访问。
并行恢复。并行的恢复机制极大的降低了数据恢复时间,提高数据的可靠性。
主机角色分配
192.168.31.80 admin(ceph-deploy,ntp服务器)
192.168.31.84 osd1(mon*1,osd*3)
192.168.31.85 osd2(mon*1,osd*3)
192.168.31.86 osd3(mon*1,osd*3)
安装配置前准备工作,在admin主机生成密钥和公钥并认证其他节点服务器
~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''~]# ssh-copy-id -i /root/.ssh/id_rsa.pub osd1
~]# ssh-copy-id -i /root/.ssh/id_rsa.pub osd2
~]# ssh-copy-id -i /root/.ssh/id_rsa.pub osd3
admin服务器安装配置:
#安装配置ntp服务器~]# cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime #修改时区~]# yum install ntp~]# vim /etc/ntp.conf server 127.127.1.0fudge 127.127.1.0 stratum 8restrict default nomodify~]# systemctl start ntpd#默认的源比较慢,这里使用阿里的源~]# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo(下载阿里云的base源)~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo(下载阿里云的epel源)~]# sed -i 's/$releasever/7.2.1511/g' /etc/yum.repos.d/CentOS-Base.repo~]# vim /etc/yum.repos.d/ceph.repo[ceph]name=cephbaseurl=http://download.ceph.com/rpm-hammer/el7/x86_64/gpgcheck=0[ceph-noarch]name=cephnoarchbaseurl=http://download.ceph.com/rpm-hammer/el7/noarch/gpgcheck=0~]# yum makecache#在admin安装ceph-deploy~]# yum install ceph-deploy#在osd1,osd2,osd3等上安装ceph包~]# yum install ceph#在远程主机上部署一个集群,并生成配置文件和集群内部认证密钥文件~]# ceph-deploy mon create-initial#在远程主机上部署一个ceph监控(mon)~]# ceph-deploy mon add node3#添加一个节点到现有的集群中,添加完成后需要在ceph.conf中添加上对应的节点,并同步~]# ceph-deploy --overwrite-conf config push node1 node2 node3#强行将修改的配置文件同步到其他节点上~]# ceph-deploy disk list node1 #查看节点的磁盘情况~]# ceph-deploy osd prepare osd1:/dev/sdc1:/dev/sdb1 osd1:/dev/sdd1:/dev/sdb2 osd1:/dev/sde1:/dev/sdb3#创建三个osdrbd create block-csdn --size=100rbd map rbd/block-csdnrbd unmap /dev/rbd0
本文出自 “马尔高” 博客,请务必保留此出处http://kgdbfmwfn.blog.51cto.com/5062471/1717970