PG详解
ceph是以对象的形式存储数据的,但是对象的存储并不会直接存储进OSD中,因为对象的size很小,在一个大规模的集群中可能有几百到几千万个对象。这么多对象光是遍历寻址,速度都是很缓慢的,也不可能在对象这一级追踪位置;并且如果将对象直接通过某种固定映射的哈希算法映射到osd上,当这个osd损坏时,对象无法自动迁移至其他osd上面。为了解决这些问题,ceph引入了归置组的概念,即PG。
# 1. PG概念
# 1.1 PG和PGP是什么?
PG = Placement Group
PGP = Placement Group for Placement purpose
pg_num = number of placement groups mapped to an OSD
When pg_num is increased for any pool, every PG of this pool splits into half, but they all remain mapped to their parent OSD.
Until this time, Ceph does not start rebalancing. Now, when you increase the pgp_num value for the same pool, PGs start to migrate from the parent to some other OSD, and cluster rebalancing starts. This is how PGP plays an important role.
(1)PG是指定存储池存储对象的目录有多少个,PGP是存储池PG的OSD分布组合个数
(2)PG的增加会引起PG内的数据进行分裂,分裂到相同的OSD上新生成的PG当中
(3)PGP的增加会引起部分PG的分布进行变化,但是不会引起PG内对象的变动
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pgp用于承载pg,建议保持pg和pgp一致,调整pg数目时会进行pg内对象分裂,调整pgp时会引起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数是一定的,这样算法设计可能会简单一点。
# 2. 原理
- 对象时如何映射进PG的?
使用静态hash函数对OID(对象ID)做hash取出特征码
用特征码与根据指定存储池里的PG数量,存储池ID做一个处理,得到的序号则是PGID。
PG会根据管理员设置的副本数量进行复制
通过crush算法存储到不同的OSD节点上(其实是把PG中的所有对象储存到节点上)
- 例如,在大小为2的复制池中,每个放置组将在两个OSD上存储对象,如下所示。
# 3. PG状态
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]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 4. PG操作
# 4.1 扩容PG
ceph osd pool set {pool-name} pg_num 128
ceph osd pool set {pool-name} pgp_num 128
2
# 4.2 查看pg,pgp数量
[root@summer163-200 ~]# summer osd pool get summerk38-frp-8974 pg_num
pg_num: 256
[root@summer163-200 ~]# summer osd pool get summerk38-frp-8974 pgp_num
pgp_num: 256
[root@summer163-200 ~]#
2
3
4
5
# 4.3 获取 PG 列表
root in summer163-200 in ~ via 🐍 v2.7.5
➜ summer pg dump
2
# 4.4 查看指定 PG 的 Acting Set 或 Up Set 中包含的 OSD
- 命令的输出会告诉你 osdmap 版本( eNNN )、PG 号( {pg-num} )、Up Set 内的 OSD ( up[] )、和 Acting Set 内的 OSD ( acting[] )。
root in summer163-200 in ~ via 🐍 v2.7.5
➜ summer pg map 2.de
osdmap e33 pg 2.de (2.de) -> up [3,1] acting [3,1]
2
3
4