ceph是以对象的形式存储数据的,但是对象的存储并不会直接存储进OSD中,因为对象的size很小,在一个大规模的集群中可能有几百到几千万个对象。这么多对象光是遍历寻址,速度都是很缓慢的,也不可能在对象这一级追踪位置;并且如果将对象直接通过某种固定映射的哈希算法映射到osd上,当这个osd损坏时,对象无法自动迁移至其他osd上面。为了解决这些问题,ceph引入了归置组的概念,即PG。
# PG概念
PG是一个逻辑概念,linux系统中可以直接看到对象,但是无法直接看到PG。它在数据寻址时类似于数据库的索引:每个对象都会固定映射进一个PG中,所以当我们要寻找一个对象时,只需要先找到对象所属的PG,然后遍历这个PG就可以了,无需遍历所有对象。而且在数据迁移时,也是以PG作为基本单位进行迁移,ceph不会直接操作对象。
PG是一种间址,PG的数量有限,记录PG跟OSD间的映射关系可行,而记录object到OSD之间的映射因为数量巨大而实际不可行或效率太低。从用途来说,搞个映射本身不是目的,让故障或者负载均衡变得可操作是目的。为了降低对数量巨大的对象的管理难度,增加一层pg来管理。可能crush算法上也有考量,没有pg的话,可能每个对象oid计算一个hash值后,再通过crush映射到osd上,是不是更容易出现冲突呢?因为对象数无法事先知道,但是有了pg,先把对象映射到pg,然后只需计算pg到osd的映射就可以了,pg数是一定的,这样算法设计可能会简单一点。
# 原理
- 对象时如何映射进PG的?
- 使用静态hash函数对OID(对象ID)做hash取出特征码
- 用特征码与根据指定存储池里的PG数量,存储池ID做一个处理,得到的序号则是PGID。
- PG会根据管理员设置的副本数量进行复制
- 通过crush算法存储到不同的OSD节点上(其实是把PG中的所有对象储存到节点上)
- 例如,在大小为2的复制池中,每个放置组将在两个OSD上存储对象,如下所示。
# PG状态
代码语言:javascript复制Creating 当创建一个池的时候,Ceph会创建一些PG(通俗点说就是在OSD上建目录),处于创建中的PG就被标记为creating,当创建完之后,那些处于Acting集合
(ceph pg map 1.0 osdmap e9395 pg 1.0 (1.0) -> up [27,4,10] acting [27,4,10],对于pg它的三副本会分布在osd.27,osd.4,osd.10上,那么这三
个OSD上的pg1.0就会发生沟通,确保状态一致)的PG就会进行peer(osd互联),当peering完成后,也就是这个PG的三副本状态一致后,这个PG就会变成active clean状态,
也就意味着客户端可以进行写入操作了。
Peering peer过程实际上就是让三个保存同一个PG副本的OSD对保存在各自OSD上的对象状态和元数据进行协商的过程,但是呢peer完成并不意味着每个副本都保存着最新的数据。
直到OSD的副本都完成写操作,Ceph才会通知客户端写操作完成。
Active 当PG完成了Peer之后,就会成为active状态,这个状态意味着主从OSD的该PG都可以提供读写了。
Clean 这个状态的意思就是主从OSD已经成功peer并且没有滞后的副本。PG的正常副本数满足集群副本数。
Degraded 当客户端向一个主OSD写入一个对象时,主OSD负责向从OSD写剩下的副本, 在主OSD写完后,
在从OSD向主OSD发送ack之前,这个PG均会处于降级状态。
而PG处于active degraded状态是因为一个OSD处于active状态但是这个OSD上的PG并没有保存所有的对象。
当一个OSDdown了,Ceph会将这个OSD上的PG都标记为降级。当这个挂掉的OSD重新上线之后,OSD们必须重新peer。
然后,客户端还是可以向一个active degraded的PG写入的。当OSDdown掉五分钟后,集群会自动将这个OSD标为out,
然后将缺少的PGremap到其他OSD上进行恢复以保证副本充足,这个五分钟的配置项是mon osd down out interval,默认值为300s。
PG如果丢了对象,Ceph也会将其标记为降级。
你可以继续访问没丢的对象,但是不能读写已经丢失的对象了。
假设有9个OSD,三副本,然后osd.8挂了,在osd.8上的PG都会被标记为降级,
如果osd.8不再加回到集群那么集群就会自动恢复出那个OSD上的数据,在这个场景中,PG是降级的然后恢复完后就会变成active状态。
Recovering Ceph设计之初就考虑到了容错性,比如软硬件的错误。当一个OSD挂了,
它所包含的副本内容将会落后于其他副本,当这个OSD起来之后,
这个OSD的数据将会更新到当前最新的状态。这段时间,这个OSD上的PG就会被标记为recover。
而recover是不容忽视的,因为有时候一个小的硬件故障可能会导致多个OSD发生一连串的问题。
比如,如果一个机架或者机柜的路由挂了,会导致一大批OSD数据滞后,
每个OSD在故障解决重新上线后都需要进行recover。
Ceph提供了一些配置项,用来解决客户端请求和数据恢复的请求优先级问题,这些配置参考上面加粗的字体吧。
Backfilling 当一个新的OSD加入到集群后,CRUSH会重新规划PG将其他OSD上的部分PG迁移到这个新增的PG上。
如果强制要求新OSD接受所有的PG迁入要求会极大的增加该OSD的负载。
回填这个OSD允许进程在后端执行。一旦回填完成后,新的OSD将会承接IO请求。在回填过程中,你可能会看到如下状态:
backfill_wait: 表明回填动作被挂起,并没有执行。
backfill:表明回填动作正在执行。
backfill_too_full:表明当OSD收到回填请求时,由于OSD已经满了不能再回填PG了。
imcomplete: 当一个PG不能被回填时,这个PG会被认为是不完整的。
同样,Ceph提供了一系列的参数来限制回填动作,包括osd_max_backfills:OSD最大回填PG数。
osd_backfill_full_ratio:当OSD容量达到默认的85%是拒绝回填请求。osd_backfill_retry_interval:字面意思。
Remmapped 当Acting集合里面的PG组合发生变化时,数据从旧的集合迁移到新的集合中。
这段时间可能比较久,新集合的主OSD在迁移完之前不能响应请求。
所以新主OSD会要求旧主OSD继续服务指导PG迁移完成。
一旦数据迁移完成,新主OSD就会生效接受请求。
Stale Ceph使用心跳来确保主机和进程都在运行,OSD进程如果不能周期性的发送心跳包,
那么PG就会变成stuck状态。默认情况下,OSD每半秒钟汇报一次PG,up thru,boot, failure statistics等信息,要比心跳包更会频繁一点。
如果主OSD不能汇报给MON或者其他OSD汇报主OSD挂了,Monitor会将主OSD上的PG标记为stale。当启动集群后,
直到peer过程完成,PG都会处于stale状态。而当集群运行了一段时间后,如果PG卡在stale状态,
说明主OSD上的PG挂了或者不能给MON发送信息。
Misplaced 有一些回填的场景:PG被临时映射到一个OSD上。而这种情况实际上不应太久,
PG可能仍然处于临时位置而不是正确的位置。这种情况下个PG就是misplaced。
这是因为正确的副本数存在但是有个别副本保存在错误的位置上。
Incomplete 当一个PG被标记为incomplete,说明这个PG内容不完整或者peer失败,
比如没有一个完整的OSD用来恢复数据了。
scrubbing 清理中,pg正在做不一致性校验。
inconsistent 不一致的,pg的副本出现不一致。比如说对象的大小不一样了。
卡住的pg状态:
Unclean: 归置组里有些对象的副本数未达到期望次数,它们应该在恢复中;
Inactive: 归置组不能处理读写请求,因为它们在等着一个持有最新数据的OSD 回到up 状态;
Stale: 归置组们处于一种未知状态,因为存储它们的OSD 有一阵子没向监视器报告了
(由mon osd report timeout 配置)
为找出卡住的归置组,执行:
ceph pg dump_stuck [unclean|inactive|stale|undersized|degraded]
未完待续。。。。