简介

本文主要介绍ceph分布式存储架构中OSDMap和PGMap的原理及相关重要信息。

Monitor 作为Ceph的 Metada Server 维护了集群的信息,它包括了6个 Map,分别是 MONMap,OSDMap,PGMap,LogMap,AuthMap,MDSMap。其中 PGMap 和 OSDMap 是最重要的两张Map,本文会重点介绍。

图A: Ceph map 结构

OSDMap

OSDMap 是 Ceph 集群中所有 OSD 的信息,所有 OSD 状态的改变如进程退出,OSD的加入和退出或者OSD的权重的变化都会反映到这张 Map 上。这张 Map 不仅会被 Monitor 掌握,OSD 节点和 Client 也会从 Monitor 得到这张表,因此实际上我们需要处理所有 “Client” (包括 OSD,Monitor 和 Client)的 OSDMap 持有情况。 实际上,每个 “Client” 可能会具有不同版本的 OSDMap,当 Monitor 所掌握的权威 OSDMap 发生变化时,它并不会发送 OSDMap 给所有 “Client” ,而是需要了解到变化的 “Client” 会被 Push,如一个新的 OSD 加入会导致一些 PG 的迁移,那么这些 PG 的 OSD 会得到通知。除此之外,Monitor 也会随机的挑选一些 OSD 发送 OSDMap。 那么如何让 OSDMap 慢慢传播呢? 比如 OSD.a, OSD.b得到了新的 OSDMap,那么 OSD.c 和 OSD.d 可能部分 PG 也会在 OSD.a, OSD.b 上,这时它们的通信就会附带上 OSDMap 的 epoch,如果版本较低,OSD.c 和 OSD.d 会主动向 Monitor pull OSDMap,而部分情况 OSD.a, OSD.b 也会主动向 OSD.c 和 OSD.d push 自己的 OSDMap (如果更新)。因此,OSDMap 会在接下来一段时间内慢慢在节点间普及。在集群空闲时,很有可能需要更长的时间完成新 Map的更新,但是这并不会影响 OSD 之间的状态一致性,因为OSD没有得到新的Map,所以它们不需要知晓新的OSDMap变更。

Ceph 通过管理多个版本的 OSDMap 来避免集群状态的同步,这使得 Ceph 丝毫不会畏惧在数千个 OSD 规模的节点变更,而导致集群可能出现的状态同步的问题。

新OSD启动OSDMap的变化

图B: 新的OSD启动OSDMap的变化

当一个新的 OSD 启动时,这时 Monitor 所掌握的最新 OSDMap 并没有该 OSD 的情况,因此该 OSD 会向 Monitor 申请加入,Monitor 再验证其信息后会将其加入 OSDMap 并标记为IN,并且将其放在 Pending Proposal 中会在下一次 Monitor “讨论”中提出,OSD 在得到 Monitor 的回复信息后发现自己仍然没在 OSDMap 中会继续尝试申请加入,接下来 Monitor 会发起一个 Proposal ,申请将这个 OSD 加入 OSDMap 并且标记为 UP 。然后按照 Paxos 的流程,从 proposal->accept->commit 到最后达成一致,OSD 最后成功加入 OSDMap 。当新的 OSD 获得最新 OSDMap 发现它已经在其中时。这时,OSD 才真正开始建立与其他OSD的连接,Monitor 接下来会开始给他分配PG。

OSD crash

图C: OSD down过程

当一个 OSD 因为意外 crash 时,其他与该 OSD 保持 Heartbeat 的 OSD 都会发现该 OSD 无法连接,在汇报给 Monitor 后,该 OSD 会被临时性标记为 OUT,所有位于该 OSD 上的 Primary PG 都会将 Primary 角色交给其他 OSD(下面会解释)。

PG 和 PGMap

图D: PG和PGMap

PG(Placement Group)是 Ceph 中非常重要的概念,它可以看成是一致性哈希中的虚拟节点,维护了一部分数据并且是数据迁移和改变的最小单位。它在 Ceph 中承担着非常重要的角色,在一个 Pool 中存在一定数量的 PG (可动态增减),这些 PG 会被分布在多个 OSD ,分布规则可以通过 CRUSH RULE 来定义。 Monitor 维护了每个Pool中的所有 PG 信息,比如当副本数是三时,这个 PG 会分布在3个 OSD 中,其中有一个 OSD 角色会是 Primary ,另外两个 OSD 的角色会是 Replicated。Primary PG负责该 PG 的对象写操作,读操作可以从 Replicated PG获得。而 OSD 则只是 PG 的载体,每个 OSD 都会有一部分 PG 角色是 Primary,另一部分是 Replicated,当 OSD 发生故障时(意外 crash 或者存储设备损坏),Monitor 会将该 OSD 上的所有角色为 Primary 的 PG 的 Replicated 角色的 OSD 提升为 Primary PG,这个 OSD 所有的 PG 都会处于 Degraded 状态。然后等待管理员的下一步决策,所有的 Replicated 如果原来的 OSD 无法启动, OSD 会被踢出集群,这些 PG 会被 Monitor 根据 OSD 的情况分配到新的 OSD 上。

PG的peering过程

图E: PG的peering过程

在 Ceph 中,PG 存在多达十多种状态和数十种事件的状态机去处理 PG 可能面临的异常, Monitor 掌握了整个集群的 OSD 状态和 PG 状态,每个PG都是一部分 Object 的拥有者,维护 Object 的信息也每个 PG 的责任,Monitor 不会掌握 Object Level 的信息。因此每个PG都需要维护 PG 的状态来保证 Object 的一致性。但是每个 PG 的数据和相关故障恢复、迁移所必须的记录都是由每个 PG 自己维护,也就是存在于每个 PG 所在的 OSD 上。

PGMap 是由 Monitor 维护的所有 PG 的状态,每个 OSD 都会掌握自己所拥有的 PG 状态,PG 迁移需要 Monitor 作出决定然后反映到 PGMap 上,相关 OSD 会得到通知去改变其 PG 状态。在一个新的 OSD 启动并加入 OSDMap 后,Monitor 会通知这个OSD需要创建和维护的 PG ,当存在多个副本时,PG 的 Primary OSD 会主动与 Replicated 角色的 PG 通信并且沟通 PG 的状态,其中包括 PG 的最近历史记录。通常来说,新的 OSD 会得到其他 PG 的全部数据然后逐渐达成一致,或者 OSD 已经存在该 PG 信息,那么 Primary PG 会比较该 PG 的历史记录然后达成 PG 的信息的一致。这个过程称为 Peering ,它是一个由 Primary PG OSD 发起的“讨论”,多个同样掌握这个 PG 的 OSD 相互之间比较 PG 信息和历史来最终协商达成一致。

OSDMap、MONMap和PGMap的获取

OSDMap获取

方法一:

执行:ceph osd dump

[root@ceph1 ~]# ceph osd dump
epoch 1012
fsid 2ba8df43-eeae-4e47-82ef-870bf47f875e
created 2020-07-02 20:54:02.803269
modified 2020-07-17 11:33:03.369658
flags sortbitwise,recovery_deletes,purged_snapdirs
crush_version 20
full_ratio 0.95
backfillfull_ratio 0.9
nearfull_ratio 0.85
require_min_compat_client jewel
min_compat_client jewel
require_osd_release luminous
pool 1 'dpool' replicated size 3 min_size 1 crush_rule 0 object_hash rjenkins pg_num 512 pgp_num 512 last_change 941 flags hashpspool stripe_width 0 application rbd
        removed_snaps [1~3]
pool 2 'ssdpool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 64 pgp_num 64 last_change 392 flags hashpspool stripe_width 0
max_osd 9
osd.0 up   in  weight 1 up_from 1006 up_thru 1010 down_at 1005 last_clean_interval [982,992) 192.168.111.20:6801/11507 192.168.111.20:6802/11507 192.168.111.20:6803/11507 192.168.111.20:6804/11507 exists,up d797e54f-38a6-42e1-84b6-ea048389040c
osd.1 up   in  weight 1 up_from 1003 up_thru 1010 down_at 993 last_clean_interval [981,992) 192.168.111.20:6809/11532 192.168.111.20:6810/11532 192.168.111.20:6811/11532 192.168.111.20:6812/11532 exists,up 7e4a81f9-28c6-458f-8996-e98b2c096750
osd.2 up   in  weight 1 up_from 1001 up_thru 1010 down_at 1000 last_clean_interval [979,992) 192.168.111.20:6805/11517 192.168.111.20:6806/11517 192.168.111.20:6807/11517 192.168.111.20:6808/11517 exists,up 493909a9-6f0b-4c37-b867-896e3de2bfe3
osd.3 down out weight 0 up_from 998 up_thru 1006 down_at 1010 last_clean_interval [972,990) 192.168.111.14:6804/29438 192.168.111.14:6805/29438 192.168.111.14:6806/29438 192.168.111.14:6807/29438 autoout,exists 4031ae32-5b97-4ef1-a0f5-499fa674d6a0
osd.4 down out weight 0 up_from 996 up_thru 1007 down_at 1010 last_clean_interval [971,990) 192.168.111.14:6800/29430 192.168.111.14:6801/29430 192.168.111.14:6802/29430 192.168.111.14:6803/29430 autoout,exists dcdebe79-ab6d-4c9e-8eaf-6e2cf542d811

方法二: 获取osdmap:ceph osd getmap -o osdmap 打印osdmap:osdmaptool --print osdmap

[root@ceph1 ~]# ceph osd getmap -o osdmap
got osdmap epoch 1012
[root@ceph1 ~]# osdmaptool --print osdmap 
osdmaptool: osdmap file 'osdmap'
epoch 1012
fsid 2ba8df43-eeae-4e47-82ef-870bf47f875e
created 2020-07-02 20:54:02.803269
modified 2020-07-17 11:33:03.369658
flags sortbitwise,recovery_deletes,purged_snapdirs
crush_version 20
full_ratio 0.95
backfillfull_ratio 0.9
nearfull_ratio 0.85
require_min_compat_client jewel
min_compat_client jewel
require_osd_release luminous

pool 1 'dpool' replicated size 3 min_size 1 crush_rule 0 object_hash rjenkins pg_num 512 pgp_num 512 last_change 941 flags hashpspool stripe_width 0 application rbd
        removed_snaps [1~3]
pool 2 'ssdpool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 64 pgp_num 64 last_change 392 flags hashpspool stripe_width 0

max_osd 9
osd.0 up   in  weight 1 up_from 1006 up_thru 1010 down_at 1005 last_clean_interval [982,992) 192.168.111.20:6801/11507 192.168.111.20:6802/11507 192.168.111.20:6803/11507 192.168.111.20:6804/11507 exists,up d797e54f-38a6-42e1-84b6-ea048389040c
osd.1 up   in  weight 1 up_from 1003 up_thru 1010 down_at 993 last_clean_interval [981,992) 192.168.111.20:6809/11532 192.168.111.20:6810/11532 192.168.111.20:6811/11532 192.168.111.20:6812/11532 exists,up 7e4a81f9-28c6-458f-8996-e98b2c096750
osd.2 up   in  weight 1 up_from 1001 up_thru 1010 down_at 1000 last_clean_interval [979,992) 192.168.111.20:6805/11517 192.168.111.20:6806/11517 192.168.111.20:6807/11517 192.168.111.20:6808/11517 exists,up 493909a9-6f0b-4c37-b867-896e3de2bfe3
osd.3 down out weight 0 up_from 998 up_thru 1006 down_at 1010 last_clean_interval [972,990) 192.168.111.14:6804/29438 192.168.111.14:6805/29438 192.168.111.14:6806/29438 192.168.111.14:6807/29438 autoout,exists 4031ae32-5b97-4ef1-a0f5-499fa674d6a0
osd.4 down out weight 0 up_from 996 up_thru 1007 down_at 1010 last_clean_interval [971,990) 192.168.111.14:6800/29430 192.168.111.14:6801/29430 192.168.111.14:6802/29430 192.168.111.14:6803/29430 autoout,exists dcdebe79-ab6d-4c9e-8eaf-6e2cf542d811

获取MONMap

方法一: 执行ceph mon dump

[root@ceph1 ~]# ceph mon dump
dumped monmap epoch 2
epoch 2
fsid 2ba8df43-eeae-4e47-82ef-870bf47f875e
last_changed 2020-07-02 20:54:05.468220
created 2020-07-02 20:53:46.939873
0: 192.168.111.14:6789/0 mon.ceph2
1: 192.168.111.20:6789/0 mon.ceph1
2: 192.168.111.34:6789/0 mon.ceph3

方法二: 获取monmap:ceph mon getmap -o monmap 打印monmap:monmaptool --print monmap

[root@ceph1 ~]# ceph mon getmap -o monmap
got monmap epoch 2
[root@ceph1 ~]# monmaptool --print monmap 
monmaptool: monmap file monmap
epoch 2
fsid 2ba8df43-eeae-4e47-82ef-870bf47f875e
last_changed 2020-07-02 20:54:05.468220
created 2020-07-02 20:53:46.939873
0: 192.168.111.14:6789/0 mon.ceph2
1: 192.168.111.20:6789/0 mon.ceph1
2: 192.168.111.34:6789/0 mon.ceph3

获取PGMap

方法一: 执行ceph pg dump

[root@ceph1 ~]# ceph pg dump | less
dumped all
version 609144
stamp 2020-07-17 14:59:29.119831
last_osdmap_epoch 0
last_pg_scan 0
full_ratio 0
nearfull_ratio 0
PG_STAT OBJECTS MISSING_ON_PRIMARY DEGRADED MISPLACED UNFOUND BYTES    LOG  DISK_LOG STATE                      STATE_STAMP                VERSION    REPORTED    UP    UP_PRIMARY ACTING ACTING_PRIMARY LAST_SCRUB SCRUB_STAMP                LAST_DEEP_SCRUB DEEP_SCRUB_STAMP           SNAPTRIMQ_LEN 
1.1ff         2                  0        2         0       0  8388608 1550     1550 active+undersized+degraded 2020-07-17 11:23:04.226308 1009'13950  1011:80674 [7,2]          7  [7,2]              7 1009'13950 2020-07-16 19:05:37.290434      1009'13950 2020-07-13 23:33:46.950174             0 
1.1fe         1                  0        1         0       0  4194304 1525     1525 active+undersized+degraded 2020-07-17 11:23:04.203585  1009'7025  1011:43152 [1,6]          1  [1,6]              1  1009'7025 2020-07-16 03:07:09.454983         957'686 2020-07-10 00:30:30.527223             0 
1.1fd         1                  0        1         0       0  4194304 1585     1585 active+undersized+degraded 2020-07-17 11:23:04.213774  1009'6985  1011:43400 [0,8]          0  [0,8]              0  1009'6985 2020-07-16 20:17:20.034665         988'911 2020-07-10 16:37:27.415463             0 

方法二: 获取pgmap:ceph pg getmap -o pgmap 怎么读取pgmap,暂时没办法;

参考链接: https://www.itdaan.com/tw/fa26aab64daffee43ac3420d403092e0