本系列文章会深刻研究 Ceph 以及 Ceph 和 OpenStack 的集成:html
(1)安装和部署缓存
(2)Ceph RBD 接口和工具数据结构
(3)Ceph 物理和逻辑结构app
(4)Ceph 的基础数据结构ide
(6)QEMU-KVM 和 Ceph RBD 的 缓存机制总结性能
(7)Ceph 的基本操做和常见故障排除方法测试
(8)基本的性能测试工具和方法ui
(9) pool 的size 和 min_size,choose 和 chooseleaf,pg scrubbing 和 repair 等概念spa
注意:
- 1:
64 active+clean
osdmap e277 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
一开始,PG 和 Ceph 集群都是 active + clean 的。pool1 的 size 和 min_size 都是 3,它的一个 pg 9.1e 分布在 OSD [5,0,3] 上。
0:
杀掉 osd.5
+ 1:
osdmap e277 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
杀掉以后 osdmap 并不会马上更新。
+ 20:
14:28:57.634378 mon.0 [INF] pgmap v5610: 64 pgs: 64 active+clean; 97071 kB data, 2379 MB used, 18056 MB / 20435 MB avail
14:49:18.850232 mon.0 [INF] osd.5 192.168.56.103:6800/11598 failed (3 reports from 3 peers after 20.000173 >= grace 20.000000)
通过 20 秒之后,mon 将 osd.5 设置为 down 状态。该时长是由配置项 osd heartbeat interval 和 osd heartbeat grace 共同决定的。见下文解释。
14:49:18.933796 mon.0 [INF] osdmap e290: 4 osds: 3 up, 4 in
up 状态的 osd 少了一个,由于 osd.5 down 了。
14:49:18.944307 mon.0 [INF] pgmap v5611: 64 pgs: 16 stale+active+clean, 48 active+clean; 97071 kB data, 2379 MB used, 18056 MB / 20435 MB avail
注意此时只有16个PG有呈现stale 状态,这 16 个 PG 的主OSD 都是 osd.5, 由于它无法上报 PG 状态给 mon 了,全部mon 将这些PG 设为 stale 状态。
HEALTH_WARN 16 pgs stale; too few pgs per osd (16 < min 20); 1/4 in osds are down
pg 9.1e is stale+active+clean, acting [5,3,0]
osd.5 is down since epoch 290, last address 192.168.56.103:6800/11598
2016-06-06:14:49:19.379867646
其中,PG 9.1e 的 acting set 保持不变,可是由于主 OSD down 了,所以 MON 将它标记为 stale 状态。
14:49:19.953801 mon.0 [INF] osdmap e291: 4 osds: 3 up, 4 in
14:49:19.966491 mon.0 [INF] pgmap v5612: 64 pgs: 16 stale+active+clean, 48 active+clean; 97071 kB data, 2379 MB used, 18056 MB / 20435 MB avail
HEALTH_WARN 52 pgs incomplete; 52 pgs stuck inactive; 52 pgs stuck unclean; too few pgs per osd (16 < min 20); 1/4 in osds are down
pg 9.1e is stuck inactive for 3135.552554, current state incomplete, last acting [3,0]
pg 9.1e is incomplete, acting [3,0] (reducing pool pool1 min_size from 3 may help; search ceph.com/docs for 'incomplete')
osd.5 is down since epoch 290, last address 192.168.56.103:6800/11598
14:49:25.487264438
6 秒钟后,PG 的 acting 由 ([5,3,0], p5) 变为 ([3,0], p3), 该 PG 的状态变为 incomplete,由于它只存在于 2 个OSD 上,这个数目小于规定的副本数3。下面是 pg 9.1e 的状态:
root@ceph1:~# ceph pg 9.1e query
{ "state": "incomplete",
"snap_trimq": "[]",
"epoch": 315,
"up": [5,3],
"acting": [5,3] }
为何 6 秒以后才发生,须要进一步研究。
+ 302:
14:54:20.348720 mon.0 [INF] osd.5 out (down for 301.434591)
301 秒以后,MON 将 osd.5 标记为 out,该时长是由配置项 mon osd down out interval 决定的。见下文分析。
14:54:20.484881 mon.0 [INF] osdmap e292: 4 osds: 3 up, 3 in
in 状态的 osd 数目从 4 变为 3,由于 osd.5 out 了。
14:54:20.493183 mon.0 [INF] pgmap v5617: 64 pgs: 12 active+clean, 52 incomplete; 97071 kB data, 2247 MB used, 13079 MB / 15326 MB avail
14:54:21.588324 mon.0 [INF] osdmap e293: 4 osds: 3 up, 3 in
14:54:21.602137 mon.0 [INF] pgmap v5618: 64 pgs: 12 active+clean, 52 incomplete; 97071 kB data, 2247 MB used, 13079 MB / 15326 MB avail
14:54:26.190982 mon.0 [INF] pgmap v5619: 64 pgs: 50 active+clean, 14 incomplete; 97071 kB data, 2376 MB used, 12950 MB / 15326 MB avail
这个时候应该有 osd.2 加入了 acting set,而后有部分对象呈现 degraded 状态,由于此时 osd.2 上尚未副本,所以开始恢复过程。
{ "state": "active+recovering",
"snap_trimq": "[]",
"epoch": 317,
"up": [5,3,2],
"acting": [5,3,2],
"actingbackfill": ["2","3","5"],}
14:54:27.401982 mon.0 [INF] pgmap v5620: 64 pgs: 1 active, 63 active+clean; 97071 kB data, 2377 MB used, 12949 MB / 15326 MB avail; 2/3 objects degraded (66.667%)
7 秒以后,数据恢复进行中,此时查看 pg 的话,其状态是 “active+recovering”。
HEALTH_WARN 1 pgs stuck unclean; recovery 2/3 objects degraded (66.667%)
pg 9.1e is stuck unclean for 3437.937873, current state active, last acting [3,0,2]
recovery 2/3 objects degraded (66.667%)
2016-06-06:14:54:27.824171144
14:54:30.871475369 HEALTH_OK
14:54:31.115118 mon.0 [INF] pgmap v5621: 64 pgs: 64 active+clean; 97071 kB data, 2377 MB used, 12949 MB / 15326 MB avail; 19173 kB/s, 0 objects/s recovering
3秒以后,恢复完成,以前的数据恢复速度为 19MB/s。
+60
14:55:10.491940 mon.0 [INF] osd.5 192.168.56.103:6800/11868 boot
osd.5 启动回来。
14:55:10.492120 mon.0 [INF] osdmap e294: 4 osds: 4 up, 4 in
osd map 马上被更新。为何启动 osd 会马上致使 osdmap 被更新,须要研究。
14:55:10.499961 mon.0 [INF] pgmap v5622: 64 pgs: 64 active+clean; 97071 kB data, 2377 MB used, 12949 MB / 15326 MB avail
14:55:10.555947545 osdmap e293 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([3,0,2], p3) acting ([3,0,2], p3)
14:55:11.075660083 osdmap e294 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
PG 的主 osd 由 osd.3 切换至 osd.5,同时将以前新加入的 osd.2 踢出去了。为何 osd.5 回来以后马上恢复其以前的主OSD位子,须要研究,有多是由于CRUSH 想保持对一样的 osdmap 所选择的 PG acting set 不变,要维持这个连续性就须要作一些牺牲,包括可能出现的 recovery 或者 backfill。
PG 几种状态的说明:
几个关键步骤:
(1)MON 将 osd.5 设置为 down 状态:从上面能看出来 MON 从 osd.5 的 3 个peers 上收到了 3 个 reports,持续了 25 秒。一个 osd 能够有多个 peers,由于它可能会出现多个 pg 的 acting set 中。
文章 CONFIGURING MONITOR/OSD INTERACTION 解释了OSD心跳检测原理。同一个 PG 内的 osd 互相经过心跳机制检测对方的状态,检测间隔是 6s,由配置项 osd heartbeat interval 肯定。若是在由 osd heartbeat grace 规定的时间内(20s)某个 OSD 都没有回复心跳,作检测的 osd 将判断这个osd为 down 并向 MON 报告,而后 MON 会更新 osd map 将其设置为 down。
(2)MON 将 osd.5 设置为 out 状态:MON 在由配置项 mon osd down out interval (默认 300s)肯定的时间区间内若是发现 osd 没有回复 up 状态,则将其状态从 in 改成 out。这会致使有新的 osd 被加入 PG,并开始数据恢复过程。恢复过程结束后,集群回到 active+clean 状态。
(3)在 osd.5 重启后,osd map 马上被更新,其状态变为 up,而后 PG 的主 OSD 马上有以前的 osd.3 变为 osd.5,并将以前加入的 osd.2 踢出去了。由于该过程当中没有数据变化,osd.5 上的数据不须要被更新,所以并无发生数据移动。
pool 的 size 设置的是一个对象包括它自身在内的目标副本数,默认为 3,表示一个对象有另外两个副本;min_size 设置的是处于 degraded 模式下的对象还能接受IO时的最小副本数。当实际副本数低于 min_size 时,该对象将是只读的。
pool size | pool min_size | 对象实际副本数 | PG/对象 状态 |
3 | N/A | 3 | PG:active + clean |
3 | 3 | 2 | 对象不能接受 IO |
3 | 2 | 2 | PG:active + degraded |
3 | 2 | 1 | 对象不能接受 IO |
3 | 2 | 0 | PG:stale |
0:
集群有4个 osd (0,2,5,3),pool 的 size 和 min_size 都是3,pg 9.1e 的 acting set 为 [5,3,0]
1:
将 osd.0 停掉。
通过上面第二部分描述的过程,在几分钟后,系统恢复 OK 状态,pg 9.1e 的 acting set 变为 [5,3,2]
2:
将 osd.5 停掉。
在其变为 out 状态后,pg 9.1e 保持在 incomplete 状态。
运行 rados ls -p pool1 命令,此时已经没法返回了,也就是说此时整个存储池都不接受 IO 了
结论:对于一个 PG 来讲,其状态(能够是多个状态的组合)必须包括 active + clean 时它才能接受 IO。
3:
将 pool 的 min_size 从 3 修改成 2。
此时 pg 状态为 active+degraded, 有对象总数 1/3 的部分对象处于降级状态( 1/3 objects degraded (33.333%))。
此时 IO 能够正常进行。
结论:PG 处于 degraded 状态不影响其 IO 能力,所以,min_size 是一个 PG 能接受IO的最小副本数。
Scrubbing 是 Ceph 保持数据完整性的一个机制,相似于文件系统中的 fsck,它会发现存在的数据不一致。scrubbing 会影响集群性能。它分为两类:
下面是默认的 osd scrub 的配置项:
root@ceph2:~# ceph --admin-daemon /var/run/ceph/ceph-osd.5.asok config show | grep scrub "osd_scrub_thread_timeout": "60", "osd_scrub_thread_suicide_timeout": "60", "osd_scrub_finalize_thread_timeout": "600", "osd_scrub_finalize_thread_suicide_timeout": "6000", "osd_scrub_invalid_stats": "true", "osd_max_scrubs": "1", "osd_scrub_load_threshold": "0.5", "osd_scrub_min_interval": "86400", "osd_scrub_max_interval": "604800", "osd_scrub_chunk_min": "5", "osd_scrub_chunk_max": "25", "osd_scrub_sleep": "0", "osd_deep_scrub_interval": "604800", "osd_deep_scrub_stride": "524288",
实验过程:
0:找到对象的 PG acting set
osdmap e334 pool 'pool1' (9) object 'Evernote_5.8.6.7519.exe' -> pg 9.6094a41e (9.1e) -> up ([5,3,0], p5) acting ([5,3,0], p5)
1:删除对象的文件
根据 pg id,osd id 以及 object name,找到 osd.5 上文件路径为 /var/lib/ceph/osd/ceph-5/current/9.1e_head/Evernote\u5.8.6.7519.exe__head_6094A41E__9,将它删除
2:设置 light scrub 周期
为了避免等一天,将osd_scrub_min_interval 和 osd_scrub_max_interval 都设为4分钟:
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_max_interval 240
{ "success": "osd_scrub_max_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_max_interval
{ "osd_scrub_max_interval": "240"}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config set osd_scrub_min_interval 240
{ "success": "osd_scrub_min_interval = '240' "}
root@ceph2:/var/run/ceph# ceph --admin-daemon ceph-osd.5.asok config get osd_scrub_min_interval
{ "osd_scrub_min_interval": "240"}
3:尝试 light scrub,发现问题
能看到 light scrub 按计划进行了,并且发现了 pg 9.1e 的问题,即有文件丢失了:
2016-06-06 18:15:49.798236 osd.5 [INF] 9.1d scrub ok 2016-06-06 18:15:50.799835 osd.5 [ERR] 9.1e shard 5 missing 6094a41e/Evernote_5.8.6.7519.exe/head//9 2016-06-06 18:15:50.799863 osd.5 [ERR] 9.1e scrub 1 missing, 0 inconsistent objects 2016-06-06 18:15:50.799866 osd.5 [ERR] 9.1e scrub 1 errors 2016-06-06 18:15:52.804444 osd.5 [INF] 9.20 scrub ok
pgmap 呈现 inconsistent 状态:
2016-06-06 18:15:58.439927 mon.0 [INF] pgmap v5752: 64 pgs: 63 active+clean, 1 active+clean+inconsistent; 97071 kB data, 2268 MB used, 18167 MB / 20435 MB avail
此时集群状态是 ERROR 状态:
health HEALTH_ERR 1 pgs inconsistent; 1 scrub errors;
除了定时的清理外,管理员也能够经过命令启动清理过程:
root@ceph1:~# ceph pg scrub 9.1e instructing pg 9.1e on osd.5 to scrub
从输出能看出来,scrubbing 是由 PG 的主 OSD 发起的。
4:尝试 deep scrub,结果相同。
手工运行命令 ceph pg deep-scrub 9.1e,它会启动深度清理,结果相同。
5:尝试 pg repair,成功
运行 ceph pg repair 9.1e,启动 PG 修复过程,结果修复成功(1 errors, 1 fixed),被删除的文件回来了,集群从新回到 OK 状态。
结论:
注意:PG repair 目前还有很多问题,根据这篇文章,它会将 primary osd 上的数据复制到其它osd上,这可能会致使正确的数据被错误的数据覆盖,所以使用须要谨慎。下面的实验将验证这个问题。
0:建立一个对象,其内容是一个含有字符串 1111 的文本文件,其PG分布在 [2,0,3] 上。
1:修改 osd.2 上文件内容为 1122
2:启动 light scrub,9.2e scrub ok,没法发现问题。这不是蛮奇怪的么??light scrub 应该会检查文件属性和大小,属性应该包括修改时间吧,应该能检查出来啊。。
3. 启动 deep scrub,9.2e deep-scrub ok,没法发现问题。这不是蛮奇怪的么??deep scrub 应该会检查对象数据的啊,数据变了,应该能检查出来啊。。。
4. 启动 pg repair,内容不变。对不在 inconsistent 状态的 PG 看来作repair 不会作什么。
5. 继续修改 osd.2 上的文件,增长内容,致其 size 改变。
6. 启动 light scrub,终于发现 shard 2: soid b2e6cb6e/text/head//9 size 931 != known size 5, 1 inconsistent objects,集群状态也变为 HEALTH_ERR。
7. 启动 deep scrub,它也一样地终于发现了问题。
8. 运行 rados get 命令,能正确获取原始文件。这说明即便集群处于HEALTH_ERR 状态,处于 active+clean+inconsistent 状态的 PG 的 IO 能正常进行。
9. 启动 pg repari,osd.2 上的文件被覆盖,回到原始内容。这说明 pg repair 也不是从主osd 向别的 osd 拷贝嘛。。
结论:
CRUSH MAP 规则中,有一条是定义选择 bucket 的方式,有 choose 和 chooseleaf 两个动做,其语法为 “step [choose|chooseleaf] [firstn|indep] <N> <bucket-type>”,比较让人费解。
step choose firstn {num} type {bucket-type}
说明:选择必定数量的指定类型的 bucket。num 一般是 pool 的 size。
step chooseleaf firstn {num} type {bucket-type}
说明:首先选择类型为 {bucket-type}的一个 bucket 集合,再从每一个 bucket 的子树中选择一个叶子节点。num 一般是 pool size。
二者能够单独使用,也可结合起来使用,比较使人费解。下面经过一系列实验来讲明。
choose n 和 m | 规则 | 结果 | 说明 |
n = 0,m = 2 | step choose firstn 0 type host step choose firstn 2 type osd |
CRUSH rule 4 x 1022 [5,9,7] CRUSH rule 4 x 1023 [0,2,3] rule 4 (replicated_ruleset_choose2) num_rep 3 result size == 3: 1024/1024 |
CRUSH 选择了 3 个host(好比 1,2,3),从第一个 host 上就选了 2 个 osd,从第二host 上再选 1 个,所以 PG 的 3 个osd,头两个在一个 host 上,第三个在另外一个host上。 |
n = 0,m = 0 | step choose firstn 0 type host step choose firstn 0 type osd |
CRUSH rule 5 x 1021 [7,6,2] CRUSH rule 5 x 1022 [5,9,3] CRUSH rule 5 x 1023 [0,2,7] rule 5 (replicated_ruleset_choose0) num_rep 3 result size == 3: 1024/1024 |
CRUSH 选择了 3 个host(好比 1,2,3),从第一个 host 上就选了 3 个 osd,所以全部 PG 的 osd 所有在一个 host 上。这不符合冗余性要求。 |
n = 0,m = 1 | step choose firstn 0 type host step choose firstn 1 type osd |
CRUSH rule 7 x 1022 [5,7] CRUSH rule 7 x 1023 [0,3] rule 7 (replicated_ruleset_choose1) num_rep 3 result size == 2: 1024/1024 |
CRUSH 选择了 3 个host(好比 1,2,3),可是只成功地从第 1 和 2 个host 上分别选了1个 osd (host3 上没有 osd,所以选择失败),结果 PG 只分布在 2 个 OSD 上。 |
n = 0,m = -1 | step choose firstn 0 type host step choose firstn -1 type osd |
CRUSH rule 6 x 1022 [5,9,7] CRUSH rule 6 x 1023 [0,2,3] rule 6 (replicated_ruleset_choose-1) num_rep 3 result size == 3: 1024/1024 |
同 n=0,m=2 |
结论:效果其实同 4.3.
num | 规则 | 结果 | 说明 |
2 | step chooseleaf firstn 2 type osd | CRUSH rule 8 x 1022 [5,9] |
选择 2 个osd,任意分布在 2 个 host 上,可能在同一个 host 上,也可能分别在两个host 上 |
0 | step chooseleaf firstn 0 type osd | CRUSH rule 9 x 1022 [5,9,3] |
选择 3 个osd,任意分布在 2 个 host 上,可能在同一个 host 上,也可能分别在两个host 上 |
1 | step chooseleaf firstn 1 type osd | CRUSH rule 10 x 1022 [5] |
选择 1 个osd。 |
-1 | step chooseleaf firstn -1 type osd | CRUSH rule 11 x 1022 [5,9] |
选择 2 个osd,任意分布在 2 个host 上,可能在同一个 host 上,也可能分别在两个host 上 |
结论:根据 {num}的情形选择若干个 osd。对于 num < 0 的情形,准确地讲,应该是选择 pool-size + num 个。
num | 规则 | 结果 | 说明 |
2 | step choose firstn 0 type host step chooseleaf firstn 2 type osd |
CRUSH rule 14 x 1022 [5,9,7] |
选择 3 个osd,前两个在一个host,另外一个在另外一个host 上 |
0 | step choose firstn 0 type host step chooseleaf firstn 0 type osd |
CRUSH rule 12 x 1022 [5,9,3] |
选择 3 个osd,都在一个 host 上 |
1 | step choose firstn 0 type host step chooseleaf firstn 1 type osd |
CRUSH rule 13 x 1022 [5,7] |
选择 2 个osd,分布在 2 个host上,这应该是由于第三个 host 没有osd可供选择 |
-1 | step choose firstn 0 type host step chooseleaf firstn -1 type osd |
CRUSH rule 15 x 1022 [5,9,7] |
选择 3 个osd,前两个在一个host,另外一个在另外一个host 上 |
结论:由于 choose 语句的 num ==0,所以首选选择 3 个 host,而后从第一个 host 开始从其子树中,按照 chooseleaf 语句中 {num}的状况选择若干个 osd,直到遍历完全部的 host 或者达到 pool size。