4. 监控 PG

CRUSH 算法把 PG 分配到 OSD 时,它会根据存储池的副本数设置,把 PG 分配到不同的 OSD 上。比如,如果存储池设置为 3 副本, CRUSH 可能把它们分别分配到 osd.1osd.2osd.3 。考虑到 CRUSH Map 中设定的故障域,实际上 CRUSH 找出的是伪随机位置,所以在大型集群中,很少能看到 PG 被分配到了相邻的 OSD 。我们把涉及某个特定 PG 副本的一组 OSD 称为 acting set 。在某些情况下,位于 acting set 中的一个 OSD down 了或者不能为 PG 内的对象提供服务,这些情形发生时无需惊慌,常见原因如下:

  • 你增加或移除了某个 OSD 。然后 CRUSH 算法把 PG 重新分配到了其他 OSD ,因此改变了 Acting Set 的构成,并且引发了 “backfill” 过程来进行数据迁移。
  • 某个 OSD down 了、重启了,而现在正在恢复( recovering )。
  • Acting Set 中的一个 OSD down 了,不能提供服务,另一个 OSD 临时接替其工作。

Ceph 靠 Up Set 处理客户端请求,它们是实际处理读写请求的 OSD 集合。大多数情况下 Up Set 和 Acting Set 是相同的。如果不同,说明可能 Ceph 正在迁移数据、某 OSD 在恢复、或者有别的问题。这种情况下, Ceph 通常表现为 “HEALTH WARN” 状态,还有 “stuck stale” 消息。

用下列命令获取 PG 列表:

  1. ceph pg dump

查看指定 PG 的 Acting Set 或 Up Set 中包含的 OSD,执行:

  1. ceph pg map {pg-num}

命令的输出会告诉你 osdmap 版本( eNNN )、PG 号( {pg-num} )、Up Set 内的 OSD ( up[] )、和 Acting Set 内的 OSD ( acting[] )。

  1. osdmap e1196 pg 0.2d (0.2d) -> up [13,30] acting [13,30]

4.1 节点互联

写入数据前,PG 必须处于 active 、而且应该clean 状态。假设某存储池的 PG 有 3 副本,为让 Ceph 确定 PG 的当前状态,PG 的主 OSD (即 acting set 内的第一个 OSD )会与第二和第三 OSD 建立连接、并就 PG 的当前状态达成一致意见。

4. 监控 PG - 图1

OSD 们也向 Mon 报告自己的状态。要排除节点互联的问题,请参考本手册第二部分 3. 常见 PG 故障处理 中的相关部分进行处理。

4.2 监控 PG 状态

如果你执行了 ceph healthceph -s 、或 ceph -w 命令,你也许注意到了集群并非总返回 HEALTH_OK 。检查完 OSD 是否在运行后,你还应该检查 PG 的状态。你应该明白,在 PG 建立连接时集群不会返回 HEALTH_OK

  • 刚刚创建了一个存储池,PG 还没达成一致。
  • PG 正在恢复。
  • 刚刚增加或删除了一个 OSD 。
  • 刚刚修改了 CRUSH Map,PG 正在迁移。
  • 某一 PG 的副本间的数据不一致。
  • Ceph 正在洗刷一个 PG 的副本。
  • Ceph 没有足够可用容量来完成回填操作。

如果是前述原因之一导致了 Ceph 返回 HEALTH_WARN ,无需紧张。很多情况下,集群会自行恢复;有些时候你得采取些措施。归置 PG 的一件重要事情是保证集群启动并运行着,所有 PG 都处于 active 状态、并且最好是 clean 状态。用下列命令查看所有 PG 状态:

  1. ceph pg stat

其结果会告诉你 PG map 的版本号( vNNNNNN )、PG 总数 x 、有多少 PG 处于某种特定状态,如 active+clean ( y )。

  1. vNNNNNN: x pgs: y active+clean; z MB data, aa MB used, bb MB / cc MB avail

除了 PG 状态之外, Ceph 也会报告数据占据的空间( aa )、剩余可用空间( bb )和 PG 总容量。这些数字在某些情况下是很重要的:

  • 集群快达到 near full ratiofull ratio 时。
  • 由于 CRUSH 配置错误致使数据没能在集群内正确分布。

PG ID

PG IDs 由存储池号(不是存储池名字)、后面跟一个点( . )、再加一个 16 进制数字的 PG ID 。用 ceph osd lspools 可查看存储池号及其名字,例如,默认存储池 rbd 对应的存储池号是 0 。完整的 PG ID 格式如下:

  1. {pool-num}.{pg-id}

典型例子:

  1. 0.1f

用下列命令获取 PG 列表:

  1. ceph pg dump

你也可以让它输出到 JSON 格式,并保存到文件:

  1. ceph pg dump -o {filename} --format=json

要查询某个 PG,用下列命令:

  1. ceph pg {poolnum}.{pg-id} query

Ceph 会输出成 JSON 格式。

  1. {
  2. "state": "active+clean",
  3. "snap_trimq": "[]",
  4. "epoch": 26760,
  5. "up": [
  6. 1,
  7. 2
  8. ],
  9. "acting": [
  10. 1,
  11. 2
  12. ],
  13. "actingbackfill": [
  14. "1",
  15. "2"
  16. ],
  17. "info": {
  18. "pgid": "0.2d",
  19. "last_update": "26708'96",
  20. "last_complete": "26708'96",
  21. "log_tail": "0'0",
  22. "last_user_version": 96,
  23. "last_backfill": "MAX",
  24. "purged_snaps": "[1~1]",
  25. "history": {
  26. "epoch_created": 1,
  27. "last_epoch_started": 26760,
  28. "last_epoch_clean": 26760,
  29. ......
  30. "recovery_state": [
  31. {
  32. "name": "Started\/Primary\/Active",
  33. "enter_time": "2016-11-05 11:01:12.719671",
  34. "might_have_unfound": [],
  35. "recovery_progress": {
  36. "backfill_targets": [],
  37. "waiting_on_backfill": [],
  38. "last_backfill_started": "0\/\/0\/\/-1",
  39. "backfill_info": {
  40. "begin": "0\/\/0\/\/-1",
  41. "end": "0\/\/0\/\/-1",
  42. "objects": []
  43. },
  44. "peer_backfill_info": [],
  45. "backfills_in_flight": [],
  46. "recovering": [],
  47. "pg_backend": {
  48. "pull_from_peer": [],
  49. "pushing": []
  50. }
  51. },
  52. "scrub": {
  53. "scrubber.epoch_start": "26752",
  54. "scrubber.active": 0,
  55. "scrubber.waiting_on": 0,
  56. "scrubber.waiting_on_whom": []
  57. }
  58. },
  59. {
  60. "name": "Started",
  61. "enter_time": "2016-11-05 11:01:11.737126"
  62. }
  63. ],
  64. "agent_state": {}
  65. }

4.3 找出故障 PG

如前所述,一个 PG 状态不是 active+clean 时未必有问题。一般来说,PG 卡住时 Ceph 的自修复功能可能会不起作用,卡住的状态细分为:

  • Unclean: PG 里有些对象的副本数未达到期望值,它们应该进行恢复。
  • Inactive: PG 不能处理读写请求,因为它们在等着一个持有最新数据的 OSD 回到 up 状态。
  • Stale: PG 处于一种未知状态,因为存储它们的 OSD 有一阵子没向 Mon 报告了(由参数 mon osd report timeout 配置)。

为找出卡住的归置组,执行:

  1. ceph pg dump_stuck [unclean|inactive|stale|undersized|degraded]

关于排除卡住的 PG 见请参考本手册第二部分 3. 常见 PG 故障处理 中的相关部分进行处理。

4.4 定位对象位置

要把对象数据存入 Ceph 对象存储, Ceph 客户端必须:

  1. 设置对象名
  2. 指定存储池

Ceph 客户端索取最新集群 map、并用 CRUSH 算法计算对象到 PG 的映射,然后计算如何动态地把 PG 分配到 OSD 。要定位对象位置,只需要知道对象名和存储池名字:

  1. ceph osd map {poolname} {object-name}
练习:定位一个对象

我们先创建一个对象。给 rados put 命令指定一对象名、一个包含数据的测试文件路径、和一个存储池名字,例如:

  1. rados put {object-name} {file-path} --pool=data
  2. rados put test-object-1 testfile.txt --pool=data

用下列命令确认 Ceph 对象存储已经包含此对象:

  1. rados -p data ls

现在可以定位对象了:

  1. ceph osd map {pool-name} {object-name}
  2. ceph osd map data test-object-1

Ceph 应该输出对象的位置,例如:

  1. osdmap e537 pool 'data' (0) object 'test-object-1' -> pg 0.d1743484 (0.4) -> up [1,0] acting [1,0]

要删除测试对象,用 rados rm 即可,如:

  1. rados rm test-object-1 --pool=data