技术文章2025 年 11 月 5 日约 7.1 分钟

Ceph 集群运维实战:常见命令、故障诊断与性能优化

命令表最大的问题不是太长,而是不告诉你哪一条会后悔。这篇把 Ceph 命令分三类,只留真正改变判断的十几条,并说清哪些动作是不可逆的。

我刚接手 Ceph 的时候收集过一份命令清单,一百多条,按"日常/管理/诊断/优化"分了四类。用了半年之后发现一个尴尬的事实:清单里真正在关键时刻救过我的不超过十几条,而其中三条曾经差点把事情弄得更糟。

问题不在于清单太长,在于它没有标注哪一条是"问",哪一条是"动"。

#一、把命令分成三类,比背下来更重要

按"它能改变什么"来分,Ceph 的命令其实只有三类:

类别特征例子什么时候用
读只看状态,不动集群ceph -s、ceph osd df tree、ceph osd perf、ceph pg dump_stuck任何时候,越多越好
问会触发一次计算或探测,但不改变数据分布ceph osd map、ceph pg <pgid> query、ceph health detail定位问题时
动改变集群状态,部分不可逆ceph osd out、ceph osd crush remove、ceph osd destroy、ceph pg repair、ceph osd lost说清楚代价之后

这张表是我认为 Ceph 运维里最该先建立的东西——因为它把"我记得这条命令"和"我知道这条命令的代价"分开了。第二件事才是值钱的。

#二、先学会读懂 ceph -s 里的沉默

ceph -s 是绝大多数人第一条学会的命令,也是最容易被读得太快的命令。它有两种读法:

bash
ceph -s
#   cluster:
#     id:     <uuid>
#     health: HEALTH_WARN
#            1 pool(s) have non-power-of-two pg_num
#   services:
#     mon: 3 daemons, quorum a,b,c (age 4d)
#     mgr: x(active, since 3d), standbys: y
#     osd: 12 osds: 12 up (since 2d), 12 in (since 2d)
#   data:
#     pools:   3 pools, 289 pgs
#     objects: 1.20M objects, 4.1 TiB
#     usage:   5.6 TiB used, 12 TiB / 18 TiB avail
#     pgs:     289 active+clean

第二行里的 since 2d / since 3d 是最容易被忽略、也最有信息量的部分。它记录的是"最后一次状态变化距今多久",等价于一个免费的变更审计:

  • osd: 12 osds: 12 up (since 2d) —— 如果这个数字比你上次巡检时小,说明两天前有 OSD 掉过又回来了,而你可能完全没收到通知。
  • mon: 3 daemons, quorum a,b,c (age 4d) —— age 突然变小,说明 Monitor 发生过重新选主。
  • pgs: 全是 active+clean 时没有信息量;一旦不是,这一行就是优先级最高的信息。

我现在的习惯是把 ceph -s 的输出连同时间戳定期落盘,用来看"变过什么",而不是"现在是什么"。能看出沉默的那部分,才算读懂了这条命令。

#三、第二层:health detail 与 osd df tree

bash
ceph health detail
ceph osd df tree
ceph osd perf
  • health detail 给的是可执行的提示(哪条规则触发、涉及哪个池/OSD)。HEALTH_WARN 有好几十种,靠记没用,看 detail。
  • osd df tree 一次回答三件事:容量分布是否均衡、每块 OSD 的 %USE 是否接近、PG 数是否均衡。注意 VAR 一列——容量和 PG 数的方差不均衡时,修法完全不同(crush weight vs pg_num/autoscaler)。
  • osd perf 给每块 OSD 的 apply/commit 延迟。集群"整体变慢但 -s 正常"时,先看这里再谈调优。

#四、"动"类命令:把可逆性标清楚

这一节是这篇真正的重点。下面每一步的"可逆性"我按自己的理解标注,动手前请以你的版本文档复核:

命令做了什么可逆吗代价
ceph osd out <id>让数据从这块 OSD 迁出可逆(osd in)触发一次完整回填,集群负载显著上升
ceph osd crush remove osd.<id>从拓扑里摘掉可重建,但要重算若在 out 未完成时执行,会连同未迁完的数据一起失去
ceph osd destroy <id>销毁该 OSD 的元数据/身份不可逆该 OSD 上的数据被视为不存在
ceph osd purge <id>一步做完 out+crush remove+auth 清理不可逆顺序错了就没有回头路
ceph pg repair <pgid>以 primary 为准修复副本不可逆地覆盖如果 primary 本身是坏的那一份,会把坏数据复制到所有副本
ceph osd lost <id> --yes-i-really-mean-it声明某 OSD 的数据永久丢失不可逆之后 PG 会把缺失副本当作"没有"来重建

要特别说 pg repair:它在"某个副本明显损坏、且你确信 primary 是好的"时是正确工具;在你不知道哪一份是对的的时候用它,等于随机选一份覆盖其余所有副本。这类命令的共同特征是——它们不会问你确定不确定,只问你打不打那个参数。

一个可操作的习惯:把上面这些命令包一层再放进脚本,让执行前必须显式确认:

bash
osd_remove() {
  local id="$1"
  echo "即将执行:out -> 等待回填 -> crush remove -> destroy"
  echo "当前该 OSD 上的 PG 数:$(ceph pg ls-by-osd osd.$id 2>/dev/null | wc -l)"
  read -r -p "确认继续?(yes) " ok
  [ "$ok" = yes ] || return 1
  ceph osd out "$id"
  while ceph -s | grep -q "recovery"; do sleep 30; done   # 等迁完,不要跳步
  ceph osd crush remove "osd.$id"
}

那个 while 循环看起来笨,但它是把"我以为迁完了"换成"命令告诉我迁完了"。顺序错一步的代价通常是数据,不是时间。

#五、故障诊断:按层走,不要跳

Ceph 的怪处在于:几乎所有的"存储问题"最后都能追到非存储的地方——网络、时钟、内存、甚至 BIOS 的电源策略。所以诊断路径比命令本身重要:

bash
# 1) 先分层:是数据面还是控制面?
ceph -s; ceph health detail

# 2) 如果是 OSD 相关,先看单块盘
ceph osd tree                      # 有没有 down/out
ceph osd perf                      # 是不是某几块特别慢
ceph osd metadata <id> | grep -i host   # 慢的几块是否在同一台机器

# 3) 同一台机器上多块盘同时慢 → 往上走一层
#    (网卡错包、CPU 抢占、内存不足、NUMA 绑核、RAID 卡缓存策略)

# 4) 控制面:Monitor 的时钟与网络
ceph mon stat
ceph daemon mon.<name> mon_status | head -20

经验上最高频的三个根因是:跨机架/跨机房带宽被打满、单机上的中断集中在少数 CPU 核、以及"以为对时是自动的"(Monitor 对时间敏感,clock skew 相关的告警很多人第一反应是加硬件,其实先核 NTP)。

#六、恢复期间的那些参数,是在选立场

bash
ceph config get osd osd_max_backfills
ceph config get osd osd_recovery_max_active
ceph config get osd osd_recovery_sleep
ceph config get osd osd_client_op_priority
ceph config get osd osd_recovery_op_priority

把恢复调快,前台业务的尾延迟就变差;调慢,集群处于冗余不足状态的时间就变长。这不是"调优",是分配:你决定把这段窗口的不适感分给用户还是分给风险。

一句实话:这件事没有统一答案,但有统一的做法——把当前取值和你为什么这么取写进运维文档。半年后的你(或者接手的同事)需要知道这个数字是"某次故障时临时调的",而不是"一直这样"。

#七、演练:没跑过的预案等于没有预案

预案这种东西,读起来都懂,执行起来都会卡。我建议至少把下面三个动作在非关键池上真跑一遍:

  1. 一次 osd out 到回填完成的完整流程——量出"多久迁完",这个数字直接决定你的恢复窗口预算。
  2. 一次 Monitor 重启——确认重启后 mon_status 恢复、客户端不断连太久。
  3. 一次"盘坏了"的模拟——osd destroy 一块可丢弃的 OSD,再把它重新加回来,走一遍 ceph-volume 的路径。

这三个动作的价值不在于"到时候会做",而在于你会发现一些文档里没写、但一定会卡住你的东西(认证残留、crush 权重没重置、systemd unit 名字对不上,诸如此类)。

#八、这篇没写什么

  • 没写完整命令表。 那类清单更适合当速查卡,而不是文章——而且它对版本的敏感性很高。这里只留下"改变判断"的那十几条。
  • 没写容量规划与硬件选型。 那是另一套前提(盘型、网络、副本策略),脱离它们给数字是误导。
  • 没写监控系统怎么搭。 Prometheus + ceph_exporter 是可选项之一,但"看什么指标"比"用什么采集"重要得多,值得单独一篇。
  • 没给参数推荐值。 上面说过理由:没有负载画像的推荐值,是把试错成本转嫁给读者。

如果只从这篇带走一句话:把"我知道这条命令"升级成"我知道这条命令不可逆"——Ceph 的绝大多数事故不是不懂原理,而是在不可逆的那一步没有停两秒。

写于 2025 年 11 月 5 日

栏目
技术文章
约
7.1 分钟
字数
4.2K
阅读
2

本文为原创记录,转载请注明出处。如果这篇替你省了时间,欢迎留言说说你踩到的坑。

同题 · related

留言 · remarks

00 条

还没有留言,来说点什么吧。

Ceph 集群运维实战:常见命令、故障诊断与性能优化 · LXH·BLOG