分布式存储Ceph
ceph介绍
ceph是一个统一的、分布式的存储系统,设计初衷式提供较好的性能
(io)、可靠性
(没有单点故障)和可扩展性
(未来可以理论上无限扩展集群规模),这三点也是集群架构所追求的。
- 统一性 :
意味着我们可以仅凭ceph这一套存储系统,同时提供块存储
和文件系统存储
、对象存储
。这三种功能,这极大地简化了不同应用需求下地部署和运维工作。 - 分布式 :
传统集群架构: 集群规模增大,mysql数据的集群规模必然也要随之增大,这完全是集中分布是思想带来的弊端。
ceph内部集群的数据共享完全通过算法算出来,根本不需要数据库这个组件,完全分布式的。
ceph分布式的缺点: 耗费cpu。
什么是块存储、文件存储、对象存储
块级与文件级概念
- 块级
磁盘的最小读写单位为扇区,1个或多个连续的扇区组成一个block块,也称之为物理块,是操作系统的读写单位。
一个逻辑文件对应一个物理块。
blockdev --getbsz /dev/sda1 查看block块大小(一个block块默认512字节)
# 512
- 文件级
文件是文件系统提供的功能,单个文件可能由一个或者多个逻辑块组成,且逻辑块之间是不连续分布的,逻辑块大于或等于物理块整数倍。
物理块与文件系统之间的映射关系为: 扇区–>物理块–>文件系统
注意 : 这么多层的转换,是需要耗费效率。
块存储 : 存储设备共享给客户端的是一块裸盘,那么该存储设备提供的就是块存储
- 特点 :
- 客户端可定制性强,可以自己制作文件系统,然后挂载使用,或者直接把操作系统安装在块存储里面。
- 用途 :
适用于给vm(虚拟机)的本地硬盘。虚拟机是用软件模拟出来的,存在不稳定因素,如果虚拟机出现down机了,可能会导致数据丢失,使用块存储有利于保护虚拟机数据的安全。
文件存储 : 存储设备共享给客户端的是文件夹,那么该存储设备提供的就是文件存储
- 特点 :
- 客户端主要操作的是文件和文件夹,客户端无法格式化制作自己的文件系统,使用的是现成文件系统,定制性差。
- 文件检索与存储过程都是在存储设备中完成的,意味着随着客户端数目的增多,存储设备的压力会越来越大,所以文件存储会限制集群的扩展规模。
- 用途:
适用于中小型规模集群的多服务器之间数据共享,并且保证一致。
对象存储 : 数据的存储分为两部分: inode(元数据) + block(真实数据) ( 数据存储的形式为key:value的形式 )。
- 特点 :
- 基于多服务器之间的数据共享,保证数据一致,并且没有文件系统的概念,
- 没有文件系统的概念,服务端不会随着客户端数目的增多而压力成倍增大。
- 用途:
适用于分布式存储,云存储。
为何要用ceph
- 高性能 :
1. 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。
2. 考虑了容灾的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架感知等。
3. 能够支持上千个存储节点的规模,支持TB到PB级的数据。
- 高可用 :
1. 副本数可以灵活控制
2. 支持故障域分隔,数据强一直性
3. 多故障场景自动进行修复自愈
4. 没有单点故障,自动管理,高可扩展性
- 去中心化 :
1. 扩展灵活
2. 随着节点增加而线性增长
- 特性丰富 :
1. 支持三种存储接口 : 块存储、文件存储、对象存储
2. 支持自定义接口,支持多种语言驱动。
Ceph系统的层次结构
自下而上,可以将Ceph系统分为四个层次
- 基础存储系统RADOS
- 基础库LIBRADOS
- 高层应用接口,包括三个部分:
- 对象存储接口(RADOS GW)
- 块存储接口(RBD)
- 文件存储接口(Ceph FS)
- 应用层 : 基于高层接口或者基础库librados开发出来的各种APP,或者主机,VM等诸多客户端
- ceph集群称之为Rados
- Rados集群是ceph的服务端,依据高层接口封装的应用则是客户端。
基础存储系统RADOS
ceph集群架构类似于一个网络版本的raid10模式
- 单台机器可插硬盘的总数是有限的,如果能通过网络通信,那么就可以打破单台机器的限制:一堆硬盘+软件控制起来
做成硬盘的集群,相当于一个大的网络raid,这就是分布式存储,比如ceph。
ceph集群的子集群
1. OSD(osd daemon)集群
- 一个osd daemon就是一个套接字应用程序,一个osd daemon唯一对应一块数据盘( 数据盘的组成可以是一块机械硬盘 + 一块固态盘的两个分区 )。
- 综合算下来,OSD集群由一定数目的osd daemon组成(osd daemon数量从几十个到几十万个不等,也有可能会更多)。
ceph的不同版本osd daemon与disk(数据盘)之间的对应关系
hammer(老版本): osd daemon --> xfs文件系统 --> disk
- xfs文件系统叫日志文件系统,先写入日志,再写入数据内容。一个disk = 一个机械盘 + 一个固态盘
- 性能优化 : 固态盘负责存文件系统日志,机械盘负责写入数据内容。
luminous(新版本): osd daemon --> 裸盘disk
- 一个disk搭配固态盘的两个分区,一个固态盘分两个分区,一个分区存日志,一个分区存元数据
- 一个固态盘两个分区下面搭配一个机械盘。
- 对比hammer版本和luminous版本,luminous版本的osd daemon是直接传输数据给数据盘的。因此,不需要经历物理块与文件系统之间的转换,读写数据效率要高于hammer版本。
osd daemon节点主要负责:
- 负责控制数据盘上的文件读写操作,与client通信完成各种数据对象操作等等
- 负责数据的拷贝和恢复
- 每一个osd daemon守护进程监视它自己的状态,以及别的osd deamon的状态,并且报告给Monitor(监控节点,控制了ceph集群的行为)
pg_temp状态
- pg组中的osd daemon也有主次之分,一个pg组里面有多个osd daemon,crush算法会默认把其中一个osd damon作为
primary osd
(主osd daemon),主osd daemon主要负责接收数据的读写;其余的作为replication osd
(从osd daemon),从osd daemon主要负责数据的备份。
- 如果pg组中的
replication osd
挂了,crush算法会默认将primary osd
的数据备份一份到新加入的replication osd
中。 - 如果pg组中的
primary osd
挂了,crush算法将一个新的osd deamon划分到这个pg组中作为primary osd
,那么crush算法会先将pg组里面原来的replication osd
暂时先作为主osd daemon。等到新划分的primary osd
备份了这个pg组里面的数据,会正式作为主osd daemon负责接收这个pg组的数据读写。发生这种现象,pg状态会短暂处于pg_temp状态。
2. MON(Montior)集群
Montior节点主要负责 :
- 监控全局状态(cluster map)
cluster map负责监控:
1. osd daemon map
2. monitor map
3. pg map
4. crush map
- 负责管理集群内部状态(osd daemon挂掉,数据恢复等操作)
- 负责授权,客户端在访问时会先通过monitor集群验证操作权限
客户端需要先跟monitor要到cluster map
ps : monitor节点的个数 = 2*n+1
- 必须为奇数个
- 一个monitor存在单点故障的问题,所以最少三个起
MON集群为何monitor节点个数应该为奇数个
- monitor节点同步数据用的是paxos算法(分布式强一致性算法),paxos算法规定至少有三个节点。
- paxos算法的作用,一个monitor节点只要数据不一致,就会通过paxos算法保证该节点的数据保持一致。
MON集群可以挂掉几个monitor节点
- monitor节点之间使用paxos算法来保持各节点cluster map的一致性;各mon节点的功能总体上是一样的,相互间的关系可以被简单理解为主备关系。如果主mon节点损坏,其他mon存活节点超过半数时,集群还可以正常运行。当故障mon节点恢复时,会主动向其他mon节点拉取最新的cluster map。
monitor进程与osd daemon进程能否在同一个物理节点上
- 可以,但是不好。但是这就是一种集中式的思想,如果可以考虑到成本,可以这么做。
Ceph集群的核心逻辑概念
ceph的特性
- 伪数据平衡,是通过算法达到的
object ---> pg组 是通过hash算法实现的
pg组 ---> osd daemon 是通过crush算法实现的
- ceph适用于海量小文件,或者单个容量大文件
pg和pool相关概念
ceph的逻辑单位
- pg(归置组) : pg是ceph中分配数据的最小单位,一个pg内包含多个osd daemon。
- pool(存储池): 我们在创建pool存储池时需要指定pg的个数,来创建pg。创建pg需要用到crush算法,crush算法决定了pg与osd daemon的对应关系,所以说,在客户端往ceph中写入数据之前,pg与osd daemon的对应关系是已经确定的。虽然是确定的,但是pg与osd daemon的对应关系是动态的。
一个osd daemon应该属于多少个pg组呢
- 首先osd daemon不能只属于一个pg组。ceph是以pg组为单位分配数据的,如果一个osd daemon只属于一个pg组,那么该osd daemon将只能接收着一个pg组发来的数据。
- 如果该pg组没有被hash算法算到,那么就不会收到数据,于是该osd daemon就被闲置了。因此,pg组与osd daemon之间的关系为多对多关系。
- 官方建议 : 如果ceph集群很长一段时间都不会拓展,一个osd deamon属于100个pg组。否则,一个osd deamon属于200个pg组。
Ceph网络划分
Ceph推荐主要使用两个网络,这么做,注意从性能(OSD节点之间会有大量的数据拷贝操作)和安全性(两网分离)考虑。
- 前端(南北)网络 : 连接客户端和集群
- 后端(东西)网络 : 连接ceph各个存储节点
pool存储池详解
Ceph的pool有四大属性
- 所有性和访问权限
- 对象副本数目,默认pool池中的一个pg只包含两个osd daemon,即一份数据交给pg后会存下2个副本,生产环境推荐设置为3个副本。
- pg数目,pg是pool的存储单位,pool的存储空间就由pg组成
- crush规则集合
pg数与osd daemon之间对应关系的影响
创建pool时需要确定其pg的数目,在pool被创建后也可以调整该数字,但是增加池中的pg数是影响ceph集群的重大事件之一,在生产环境中应该避免这么做。因为pool中的pg的数目会影响到:
- 数据的均匀分布性
- 资源消耗:pg作为一个逻辑实体,它需要消耗一定的资源,包括内存,CPU和带宽,太多的pg的话,则占用资源会过多
- 清理时间:Ceph的清理工作是以pg为单位进行的。如果一个pg内的数据太多,则其清理时间会很长
- 数据的持久性:pool中的pg个数应该随着osd daemon的增多而增多,这样crush算法可以将pg和osd的对应关系尽量均匀一些,降低同一个osd属于很多个pg的几率,如果一个osd真的属于很多很多pg,这样可能会很糟糕,可能会出现如下情况:
假设我们pool副本的size为3,则表示每一个pg将数据存放在3个osd上。一旦某个osd daemon挂掉,因为一个osd daemon同时属于很多个pg,则此时会出现很多pg只有2个副本的情况,这个时候通过crush算法开始进行数据恢复。在数据恢复的过程中,因为数据量过大,又有一个osd daemon(也属于很多很多pg)扛不住压力也崩溃掉了,那么将会有一部分pg只有一个副本。这个时候通过crush算法再次开始进行数据恢复,情况继续恶化,如果再有第三个osd daemon挂掉,那么就可能会出现部分数据的丢失。
由此可见,osd daemon上的pg组数目:
- 不能过小,过小则数据分布不均匀
- 不能过大,过大则一个osd daemon挂掉影响范围会很广,这会增大数据丢失的风险
osd daemon上的pg组数目应该是在合理范围内的,我们无法决定pg组与osd daemon之间的对应关系,这个是由crush算法决定的。但是我们可以在创建pool池时,可以指定pool池内所包含pg的数量,只要把pg的数量设置合理,crush算法自然会保证数据均匀。
指定pool池中pg的数量
如何算出一个pool池内应该有多少个pg数?
- Target PGs per OSD:crush算法为每个osd daemon分配的pg数(官网建议100或200个)
- OSD#:osd daemon的总数
- %DATA:该存储池的空间占ceph集群整体存储空间的百分比
- Size:pool池中的副本数
计算公式:
(Target PGs per OSD)✖(OSD#)✖(%DATA)/Size
如果如果ceph集群很长一段时间都不会拓展,我们osd daemon的总数为9,该存储池占用整个ceph集群整体存储空间的百分比为1%(10G/1000G),
pool池中的副本数为3个,那么我们在pool池中设置pg的数量为多少合理?
100 * 9 * 0.01 / 3 = 3 (个)
官网也给出了一些参考原则
- osd daemon的总数少于5个,建议将pool中的pg数设为128
- osd daemon的总数5到10个,建议将pool中的pg数设为512
- osd daemon的总数10到50个,建议将pool中的pg数设为4093
osd daemon的总数为50个以上,我们可以使用官网的工具进行计算,来确定pool池中pg的个数。ceph官网计算工具网址:https://ceph.com/pgcalc/
Ceph中pool池的两种类型
- Replicated pool(默认)
副本型pool,通过生产对象的多份拷贝
优点 : 保证了数据的安全
缺点 : 浪费空间,如果设置的pg对应三个副本,那么空间只能用到原来空间的三分之一 - Erasure-coded pool
特点 : 没有副本,可以把空间百分之百利用起来,但是没有副本功能(无法保证数据的安全)
不支持ceph的压缩,不支持ceph垃圾回收的功能等
pg逻辑单位详解
pg概念
- Acting set : 支持一个pg组所有osd daemon的有序列表,其中第一个osd是主osd,其余为次。acting set是crush算法分配的,但是不一定已经生效了。Acting set是由crush算法计算得出的。
- PG temp:Ceph正在往主osd daemon回填数据时,这个主osd是不能提供数据服务的,这个时候,它回向Monitor集群申请一个临时的Acting set,这就是PG temp。
举个例子,现在acting set是[0,1,2],出现了一点事情后,它变为了[3,2,1]。此时,osd.3还是空的,它无法提供数据服务,因此它还需要等待回填数据过程结束。这时候,osd.3会向monitor集群申请一个临时的set [1,2,3]。此时,将由osd.1提供数据服务。回填数据过程结束后,该临时的set会被丢弃,重新由osd.3提供服务。
- 主(primary)OSD:在acting set中的首个OSD,负责接收客户端写入的数据;默认情况下,提供数据读服务,但是该行为可以被修改。它还负责peering过程,以及在需要的时候申请PG temp。
- 次(replica)OSD:在acting set中除了第一个以外的其余OSD。
- 流浪(stray)OSD:已经不是acting set中了,但是还没有被告知去删除数据的OSD。
pg的状态
其主要状态包括
- Creating 创建中:pg组正在被创建。
- Peering 对等互联:Peering就是一个pg组的所有的osd daemon都需要互相通信,pg组的对象及其元数据的状态达成一致的过程。
- Active 活动的:Peering的过程完成之后,pg组的状态就是active的。此状态下,主次的osd daemon上的pg组数据都是可用的,即pg组内主osd daemon和从osd daemon都处于就绪状态,可正常提供客户端请求。
- Clean 洁净的:此状态下,主次osd daemon都已经处于就绪状态,每个副本都就绪了。
- Down:pg掉线了。
- Degraded 降级的:某个osd daemon被发现停止服务(down)了之后,Ceph的Montior集群将该osd daemon上所有的pg的状态设置为degraded,即pg包含的osd数目不够,此时该osd daemon的对等osd daemon会继续提供数据服务。这时会有两种结果:
- down掉的osd daemon会重新起来,需要再经过Peering到clean的状态,而且Ceph会发起恢复过程(recovering 增量恢复),使用该osd daemon上过期的数据被恢复到最新状态。
- osd daemon的down状态持续300秒后其状态被设置为out提出集群,Ceph会启动自恢复操作,选择其他的osd daemon加入acting set,并启动回填数据(backfilling 全量恢复)到新的osd daemon的过程。使pg副本数恢复到规定的数目,有时候崩溃的时候也会处于此状态。
- Remapped 重映射:每当pg的acting set改变后,就会发生从旧的acting set到新的acting set的数据迁移。此过程结束前,旧的acting set中的主osd daemon将继续提供服务。一旦该过程结束,Ceph将使用新的acting set中的主osd dameon来提供服务。
- Stale 过期的:每个osd daemon每隔0.5秒向monitor集群报告其状态。如果因为任何原因,主osd daemon报告状态失败了,或者其他osd daemon已经报告了主osd daemon状态为down了,monitor集群将会将他们的pg标记为stale状态。
- Undersized: 当pg中副本数少于其他存储池指定的个数的时候,就为此状态。
- Scrubbing:osd daemon会周期性的检查其持有的数据对象的完整性,以确保主osd daemon和从osd daemon数据的一致,这时候状态就为此状态。另外pg偶尔还需要检查确保一个对象的osd daemon能按位匹配,这时候状态为scrubbing + deep。
- recovering:增量恢复。
- backfilling:全量恢复。
- unkown:表示pg不知道与哪些osd daemon对应。出现这种状态,表示指定的Crush规则错误了。
Crush规则详解
什么是Crush
- Crush是一种类似于一致性hash的算法,用于为Rados存储集群控制数据分布
Crush在ceph集群中的作用
- 负责数据从pg组到osd daemon的存取
Crush rules(规则)的三个作用
- 指定从Crush Map中的哪个节点开始查找
- 指定使用哪个节点作为故障隔离域
- 指定定位副本的搜索模式(广度优先or深度优先)
自定义Crush规则
rule nana_rule { # 规则集的命名,创建pool时可以指定rule集
id 1 # id设置为1
type replicated # 定义pool池类型为replicated(还有esurecode模式)
min_size 1 # pool中最小指定的副本数量不能小于1
min_size 10 # pool中最大指定的副本数量不能大于10
# pg到osd daemon的检索步骤
step take datacenter0 # 定义pg查找副本的入口点datacenter0
# 这一步选择一个根节点,这个节点不一定是root
# 这个节点可以是任何一个故障域
# 从指定选择的这个节点开始执行
step chooseleaf firstn 0 type rack # firstn 0表示算法(深度优先),type rack表示故障域设置为rack
step emit # 结束,返回结果
}
如果有三个osd 物理节点,然后他们都放在同一个机柜里,故障域应该设置为host;最好是放在三个不同的机柜里,然后故障域设置为rack。
故障域
Ceph集群中的默认的故障域,目的是为了防止单点故障
- osd:硬盘
- host:服务器
- chassis:机箱
- rack:机架(一个机架包含多个机箱)
- row:机排
- pdu:配电单元(有可能多个机排共用一个配电单元)
- pod:多个机排
- room:机房
- datacenter:数据中心(有可能多个机房组成一个数据中心)
- region:区域(华东区1,华东区2等)
- root:最顶级,必须存在
存储引擎
hammer版本的存储引擎 : filestore
filestore : osd daemon --> xfs文件系统 --> 磁盘
luminous版本的存储引擎 : bluestore
bluestore : osd daemon --> 裸磁盘
luminous版本我们通常会osd daemon --> lvm --> 裸磁盘
,让osd daemon直接对应一个lvm。那么我们为什么要这么做?
如果我们在ceph集群即将用满的情况下进行扩容,那么该如何扩容?
- osd daemon --> 裸磁盘
新增一块磁盘,然后用osd daemon管理它。但问题是,新增的一个osd daemon,ceph会在该osd aemon上创建一个pg,说白了就是把该osd daemon划分到一些pg组里面。但凡osd daemon被分配到pg里,会发生数据迁移。生产环境中,pg的数量能不动则不动。 - osd daemon --> lvm --> 裸磁盘
从vg组里面划分更多的空间给lvm,不必新增osd daemon,后期的扩容,不会发生数据迁移。
考虑到集群日后的扩容,那么推荐使用方案:osd daemon --> lvm --> 裸磁盘