Files
wiki/存储/Ceph/知识库/04-RADOS-排障篇.md
T
2026-09-18 13:49:11 +08:00

132 KiB
Raw Blame History

基于 Ceph 官方文档整理 | 文档版本:Tentacle v20.2.4 | 抓取日期:2026-09-17 | 源文:ceph/ceph@v20.2.4 doc/rados/troubleshooting/ 官网入口:https://docs.ceph.com/en/tentacle/rados/troubleshooting/

第 04 册 · RADOS 排障篇


本册导读

本册覆盖 Ceph RADOS 子系统官方排障文档的全部 8 个页面,交付一份"照着做就能排障"的中文手册。

覆盖页面清单

# 页面(rst 文件名) 官方页面标题 官网 URL 本册对应章节
1 index.rst Troubleshooting https://docs.ceph.com/en/tentacle/rados/troubleshooting/ 本册导读
2 log-and-debug.rst Logging and Debugging https://docs.ceph.com/en/tentacle/rados/troubleshooting/log-and-debug/ 第二章
3 troubleshooting-mon.rst Troubleshooting Monitors https://docs.ceph.com/en/tentacle/rados/troubleshooting/troubleshooting-mon/ 第三章
4 troubleshooting-osd.rst Troubleshooting OSDs https://docs.ceph.com/en/tentacle/rados/troubleshooting/troubleshooting-osd/ 第四章
5 troubleshooting-pg.rst Troubleshooting PGs https://docs.ceph.com/en/tentacle/rados/troubleshooting/troubleshooting-pg/ 第五章
6 cpu-profiling.rst CPU Profiling https://docs.ceph.com/en/tentacle/rados/troubleshooting/cpu-profiling/ 第六章
7 memory-profiling.rst Memory Profiling https://docs.ceph.com/en/tentacle/rados/troubleshooting/memory-profiling/ 第七章
8 community.rst The Ceph Community https://docs.ceph.com/en/tentacle/rados/troubleshooting/community/ 第八章

官方 index.rst 对排障篇的定位原文:你可能会遇到需要检查配置(configuration)、查阅文档、调整日志输出、排查 monitor 与 OSD、剖析内存与 CPU 占用,以及在最后手段下向 Ceph 社区求助的情况。本册即按这条主线组织。

排障方法论总览:先看什么 → 再查什么 → 如何定位

官方在多处反复强调的一条铁律:先 MON,后网络,再 OSD,最后 PG。troubleshooting-osd.rst 开篇即写明——在排查 OSD 之前,先检查 monitor 与网络:先确认 monitor 是否有 quorum(ceph health / ceph -s 显示 HEALTH_OK),如果 monitor 没有 quorum 或状态有错误,必须先解决 monitor 问题再往下走;然后再检查网络(主机侧看丢包,交换机侧看 CRC 错误)。

┌───────────────────────────────────────────────────────────────────┐
│  第 0 步  现象确认                                                  │
│  ceph health detail        ← 拿第一手告警原文(含 PG/OSD/MON 状态)  │
└───────────────────────────┬───────────────────────────────────────┘
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│  第 1 步  MON 层(最高优先级)                                      │
│  · ceph-mon / ceph-mgr 进程是否在跑                                 │
│  · 能否连上 MON 节点(tcp/3300、tcp/6789;iptables / nf_conntrack) │
│  · ceph status 有没有回包 → 有回包说明 quorum 已形成                 │
│  · 逐个 MON 问:ceph tell mon.ID mon_status                        │
│  任一环节不通 → 进入第三章,不要再往下查 OSD/PG                      │
└───────────────────────────┬───────────────────────────────────────┘
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│  第 2 步  网络层                                                    │
│  netstat -a/-l/-p | grep ceph;netstat -s;dmesg | grep scsi        │
│  主机侧丢包 / 交换机侧 CRC 错误 / private 网络降级(→ flapping)      │
└───────────────────────────┬───────────────────────────────────────┘
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│  第 3 步  OSD 层                                                    │
│  ls /var/log/ceph → 日志;ceph daemon osd.N help → admin socket     │
│  df -h(空间);iostat -x(I/O);ceph osd df / ceph df(容量分布)    │
│  ceph osd tree down(谁 down 了);dmesg / smartctl(硬盘)            │
│  → 第四章:起不来 / down / 满 / 慢请求 / flapping                     │
└───────────────────────────┬───────────────────────────────────────┘
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│  第 4 步  PG 层                                                     │
│  ceph pg dump_stuck stale / inactive / unclean → 先分大类            │
│  ceph pg <id> query → 看 recovery_state,定位被谁 block              │
│  rados list-inconsistent-pg <pool> → 不一致 PG                       │
│  → 第五章:unfound / incomplete / stale / inconsistent / down        │
└───────────────────────────┬───────────────────────────────────────┘
                            ▼
┌───────────────────────────────────────────────────────────────────┐
│  第 5 步  深挖:调日志级别 → 复现 → 剖析 → 求助                       │
│  debug_*/ 动态调级(第二章)→ CPU/内存剖析(第六、七章)              │
│  → 备好日志向社区求助(第八章)                                       │
└───────────────────────────────────────────────────────────────────┘

💡 补充:官方原文并未给出上面这张"五级流水线"图,它是把 troubleshooting-osd.rst 开篇的 "check the monitors and the network first"、troubleshooting-mon.rst 的 "Initial Troubleshooting" 四步、以及 troubleshooting-pg.rst 的 dump_stuck 三分类,按依赖顺序串起来的一套可执行流程。每一步的具体命令均出自源文档,没有新增未经官方文档确认的操作。

三条贯穿全篇的排戒律

  1. 不要迷信 ceph df 的"整体使用率"——troubleshooting-osd.rst 明确:看 ceph df 输出时要特别关注最满的那个 OSD,而不是 raw 空间使用百分比。只要池子里有一个 OSD 满了,写到这个池的所有 I/O 都可能失败;ceph df 报可用空间时是按"池中最满 OSD"算的。
  2. 调日志是有代价的,用完一定要调回去——log-and-debug.rst 警告:冗余日志有时每小时产生超过 1 GB 数据,OS 盘写满会导致该节点停止工作;而且 debug 输出会拖慢系统,这种延迟有时会掩盖住竞态条件(race conditions)。系统恢复正常后必须把多余的调试设置删掉。
  3. 破坏性命令只在"确认无其他副本"时用——ceph osd lost、ceph pg <id> mark_unfound_lost delete、删 PG 目录、ceph-mon --inject-monmap,官方文档都给了警告,本册在对应位置原样保留。

一、排障总纲:第一手信息与常用定位命令

1.1 日志位置与获取方式

类别 位置 / 命令 说明
通用日志目录 /var/log/ceph Ceph 日志文件默认存放于此;容器化部署(containerized deployments)通常记在 /var/log 下的其他位置
列出日志文件 ls /var/log/ceph 路径被改过或在容器里就不一定在这个目录
MON 日志 /var/log/ceph/ceph-mon.FOO.log* FOO 为 MON ID
MON 日志真实路径查询 ceph-conf --name mon.FOO --show-config-value log_file 当默认位置被改过时用它定位
OSD 日志命名 /var/log/ceph/$cluster-$name.log troubleshooting-osd.rst 举例:长期开高日志级别时,建议把一块盘挂到这个默认日志路径上
heap profile 输出 /var/log/ceph/ tcmalloc heap profiler 的 dump 落在日志目录,形如 ceph-osd.0.profile.0001.heap
admin socket 目录 /var/run/ceph 用 ls /var/run/ceph 列出各守护进程的 socket
MON admin socket /var/run/ceph/ceph-mon.ID.asok 默认值可被覆盖;容器里常常不在默认位置
MON admin socket 路径查询 ceph-conf --name mon.ID --show-config-value admin_socket 或者查 ceph.conf 里的替代路径

获取日志的三种途径(按可用性降序):

# 1) 直接读文件(最常用)
ls /var/log/ceph

# 2) 通过 admin socket 拿运行时信息(守护进程必须活着)
ls /var/run/ceph
ceph daemon {daemon-name} help          # 例如 ceph daemon osd.0 help
ceph daemon {socket-file} help          # 也可直接给 /var/run/ceph 下的 socket 文件

# 3) 用 ceph-conf 反查被改过的路径
ceph-conf --name mon.FOO --show-config-value log_file
ceph-conf --name mon.ID --show-config-value admin_socket

admin socket 能干的事情(troubleshooting-osd.rst 列举):

  • Listing Ceph configuration at runtime —— 运行时列出 Ceph 配置
  • Dumping historic operations —— 导出历史操作
  • Dumping the operation priority queue state —— 导出操作优先级队列状态
  • Dumping operations in flight —— 导出正在飞行中的操作
  • Dumping perfcounters —— 导出性能计数器

1.2 ceph health detail:排障的第一条命令

几乎所有排障场景,官方文档的第一句话都是"跑 ceph health detail"。ceph health 只给一行结论,detail 才给出哪个 OSD / 哪个 PG / 哪个 MON 出问题。

ceph health
# HEALTH_WARN 1/3 in osds are down

ceph health detail
# HEALTH_WARN 1/3 in osds are down
# osd.0 is down since epoch 23, last address 192.168.106.220:6800/11080

health detail 在本册各场景下的典型输出形态(后面章节会逐一展开):

场景 ceph health detail 输出样例
MON down mon.a (rank 0) addr 127.0.0.1:6789/0 is down (out of quorum)
时钟偏移 mon.c addr 10.10.0.1:6789/0 clock skew 0.08235s > max 0.05s (latency 0.0045s)
OSD full HEALTH_ERR 1 full osd(s); 1 backfillfull osd(s); 1 nearfull osd(s) + osd.3 is full at 97%
OSD nearfull HEALTH_WARN 1 nearfull osd(s)
PG peering 失败 HEALTH_ERR 7 pgs degraded; 12 pgs down; 12 pgs peering; ... + pg 0.5 is down+peering
PG unfound HEALTH_WARN 1 pgs degraded; 78/3778 unfound (2.065%) + pg 2.4 is active+degraded, 78 unfound
PG stale HEALTH_WARN 24 pgs stale; 3/300 in osds are down + pg 2.5 is stuck stale+active+remapped, last acting [2,0]
PG inconsistent HEALTH_ERR 1 pgs inconsistent; 2 scrub errors + pg 0.6 is active+clean+inconsistent, acting [0,1,2]

1.3 ceph -w

⚠️ 文档未明确:ceph -w(watch,持续观察集群事件流)这一命令未出现在本册源文(rados/troubleshooting/ 全部 8 个 rst)中,官方文档在此处没有给出它的用法、输出格式或退出方式。

💡 补充:之所以在排障方法论里值得一用,是因为本册反复出现的 slow requests、flapping、synchronizing 这类现象都是随时间变化的,单次快照容易漏掉;持续观察能抓到"MON 状态在 synchronizing ↔ electing 之间来回跳"、"OSD 被反复 mark down 又 up"这类只有连续采样才看得见的模式。该命令属于 Ceph 通用管理命令,此处仅作提示,具体行为请以所用版本的 ceph --help / 官方 man page 为准。

1.4 常用定位命令清单

下表中所有命令均出自本册源文档,按用途归类。

命令 用途
—— 集群整体 ——
ceph health 一行式健康结论
ceph health detail 带对象明细的健康输出(排障第一命令)
ceph status / ceph -s 集群状态;MON 只在 quorum 已形成时才应答 status 请求
ceph status -m mymon1 用 -m 显式指定连接某个 MON(默认 ceph -s 是随便挑一个 MON 连)
ceph report 生成一份完整集群报告,向社区求助时建议附上(见第八章)
ceph time-sync-status Luminous 及以后:检查时钟偏移
ceph df 集群整体数据用量与池间分布;关注最满的 OSD
ceph osd df 逐个 OSD 展示 fullness(数据占用)
—— MON ——
ceph tell mon.ID mon_status 逐个问单个 MON 的状态(即使没有 quorum 也能问)
ceph tell mon.<id> mon_status 同上
ceph --admin-daemon <full_path_to_asok_file> <command> 知道 asok 全路径时,绕过 MON 直接打 admin socket
ceph daemon mon.FOO config show 查看该 MON 当前全部配置值
ceph daemon mon.FOO config get 'OPTION_NAME' 查看该 MON 某个配置项的当前值
ceph daemon mon.FOO config set debug_mon 10/10 无 quorum 时通过 admin socket 直接改配置
ceph tell mon.FOO config set debug_mon 10/10 有 quorum 时给指定 MON 注入配置
ceph tell mon.* config set debug_mon 10/10 有 quorum 时给所有 MON 注入配置
ceph mon getmap -o /tmp/monmap 有 quorum 时:从 quorum 取 monmap
ceph-mon -i ID-FOO --extract-monmap /tmp/monmap 无 quorum 时:从已停止的 MON 直接抽取 monmap
ceph-mon -i ID --inject-monmap /tmp/monmap 把 monmap 注入已停止的 MON(危险,见第三章)
ceph-conf --name mon.ID --show-config-value admin_socket 查 MON admin socket 路径
ceph-conf --name mon.FOO --show-config-value log_file 查 MON 日志文件路径
—— OSD ——
ls /var/log/ceph 列出 Ceph 日志文件
ls /var/run/ceph 列出守护进程 admin socket
ceph daemon {daemon-name} help 列出该守护进程支持的 admin socket 命令
ceph daemon {daemon-name} config show | less 运行时查看配置(如 ceph daemon osd.0 config show)
ceph tell {daemon-type}.{daemon id or *} config set {name} {value} 运行时注入调试配置(如 ceph tell osd.0 config set debug_osd 0/5)
ceph osd tree 看 OSD 拓扑(monitoring OSDs 常用手段)
ceph osd tree down 只看处于 down 的 OSD
ceph osd df 各 OSD fullness
ceph osd dump | grep flags 查看 osdmap 上的 flag(如 flags no-up,no-down)
ceph osd dump | grep pool 列出池编号(配合 PG ID N.xxxxx 使用)
ceph osd listpools 列出池编号
ceph osd set noout / ceph osd unset noout 全局 noout(官方不推荐在 post-Luminous 使用)
ceph osd add-noout osd.0 / ceph osd rm-noout osd.0 给单个 OSD 加/去 noout(Luminous+ 更安全的做法)
ceph osd set-group noout prod-ceph-data1701 给整个 CRUSH bucket 加 noout
ceph osd unset-group noout prod-ceph-data1701 给整个 CRUSH bucket 去 noout
ceph osd set noup / ceph osd unset noup 阻止 OSD 被 mark up(治 flapping)
ceph osd set nodown / ceph osd unset nodown 阻止 OSD 被 mark down(治 flapping)
ceph osd set-nearfull-ratio <float[0.0-1.0]> 调 nearfull 阈值
ceph osd set-full-ratio <float[0.0-1.0]> 调 full 阈值
ceph osd set-backfillfull-ratio <float[0.0-1.0]> 调 backfillfull 阈值
ceph osd lost 1 告知集群 osd.1 已 lost,让它尽力恢复(危险)
ceph osd force-create-pg <pgid> 强制创建(空)PG
ceph osd crush rule ls 列出 CRUSH rule
ceph osd crush rule dump erasurepool dump 某条 CRUSH rule(看约束)
ceph osd getcrushmap > crush.map 导出 CRUSH map 供离线实验
ceph osd erasure-code-profile set myprofile k=5 m=3 建更低要求的 EC profile
ceph osd erasure-code-profile set myprofile crush-failure-domain=osd 允许同一 host 上的 OSD 进同一 PG
ceph daemon osd.<id> dump_historic_ops 导出历史 op + 每个 op 经历的事件(调 slow request 核心)
ceph daemon osd.<id> dump_ops_in_flight 导出正在飞行中的 op
ceph config set osd osd_op_num_shards_hdd 1 改 HDD OSD shard 数(治 mClock 慢请求,需重启 OSD)
ceph config set osd osd_op_num_threads_per_shard_hdd 5 改每 shard 线程数(同上)
—— PG ——
ceph pg dump_stuck stale 列卡在 stale 的 PG
ceph pg dump_stuck inactive 列卡在 inactive 的 PG
ceph pg dump_stuck unclean 列卡在 unclean 的 PG
ceph pg 0.5 query 查 PG 卡住的原因(看 recovery_state)
ceph pg 2.4 list_unfound [starting offset, in json] 列出 unfound 对象
ceph pg 2.5 mark_unfound_lost revert|delete 把 unfound 对象标记为 lost(危险)
ceph pg repair {placement-group-ID} 修复 inconsistent PG(如 ceph pg repair 1.4)
rados list-inconsistent-pg rbd 列出 rbd 池里 inconsistent 的 PG
rados list-inconsistent-obj 0.6 --format=json-pretty 列出某 PG 内 inconsistent 的对象明细
—— 主机/系统层 ——
df -h 文件系统剩余空间
iostat -x 识别 I/O 相关问题
dmesg | grep scsi 内核诊断消息(磁盘/驱动错误)
dmesg -T 人类可读时间戳(避免把旧错误当新错误)
netstat -a | grep ceph Ceph 相关连接
netstat -l | grep ceph Ceph 监听端口
sudo netstat -p | grep ceph Ceph 相关进程
netstat -s 网络统计
smartctl 硬盘健康(来自 smartmontools 包)
sysctl -w kernel.pid_max=4194303 临时提高最大线程数
—— 剖析 ——
ceph tell {daemon-type}.{daemon-id} heap start_profiler 启动 tcmalloc heap profiler
ceph tell {daemon-type}.{daemon-id} heap stats 打印 heap 统计(不需要 profiler 在跑,也不落文件)
ceph tell {daemon-type}.{daemon-id} heap dump dump heap(必须 profiler 在跑)
ceph tell {daemon-type}{daemon-id} heap release 释放 tcmalloc 已分配但没用到的内存
ceph tell {daemon-type}.{daemon-id} heap stop_profiler 停止 heap profiler
google-pprof --text {path-to-daemon} {log-path/filename} 查看 profiler 日志
opcontrol --start / --stop / --reset oprofile 启停与重置
opreport -gal ./cmon | less 取 top cmon 结果
opreport -cal ./cmon | less 取 top cmon 结果(带 call graph)
—— CRUSH 离线实验 ——
crushtool --decompile crush.map > crush.txt 反编译 CRUSH map
crushtool --compile crush.txt -o better-crush.map 重新编译 CRUSH map
crushtool -i crush.map --test --show-bad-mappings --rule 1 --num-rep 9 --min-x 1 --max-x $((1024 * 1024)) 离线测映射(不改集群)
crushtool -i better-crush.map --test --show-bad-mappings --show-choose-tries --rule 1 --num-rep 9 --min-x 1 --max-x $((1024 * 1024)) 同上,附尝试次数直方图

引自:Troubleshooting、Troubleshooting Monitors、Troubleshooting OSDs、Troubleshooting PGs


二、日志与调试(log-and-debug.rst)

2.1 核心原则

log-and-debug.rst 开篇就讲了这套机制:Ceph 各组件的 debug 日志级别可以在运行时(at runtime)调整,服务不用停。某些情况下你也可能需要把级别写进 ceph.conf 或中央配置库(central config store)。

三条必须记住的警告:

警告 原文要点
延迟会掩盖 bug 记住 debug 输出会拖慢系统,这种延迟有时会掩盖住竞态条件(race conditions)
日志能撑爆 OS 盘 冗余日志有时每小时产生超过 1 GB 数据;如果操作系统所在磁盘("OS disk")被写满,该节点会停止工作
用完要还原 系统恢复正常后,删掉不必要的调试设置,确保集群以最优状态运行;记录 debug 输出是慢操作,且浪费集群资源

按需、分组件开启的做法:debug 日志是资源密集型(resource intensive)的。如果问题出在集群某个特定组件,只给那个组件开日志。举例:OSD 跑得好好的、只有 CephFS 的 MDS 有问题,那就只给有问题的那几个具体实例开;然后按需要逐个 subsystem 逐步开。

2.2 日志级别模型:log level / memory level

每个 subsystem 有两个可独立设置的级别:

  • log level:输出到日志文件(output logs)的级别
  • memory level:留在内存日志(in-memory logs)中的级别

取值范围 1 ~ 20,1 最简略(terse),20 最详尽(verbose)。在少数情况下级别可以取大于 20 的值,产生的日志极其详尽(extremely verbose)。

内存日志何时会被送到输出日志? 只有以下三种情况之一成立:

  1. 触发了 fatal signal(致命信号),或
  2. Ceph 代码里的 assertion 被触发,或
  3. 手动触发了把内存日志送去输出日志(即通过 admin socket 提交命令,参见 Ceph Administration Tool 文档中提交 admin socket 命令的示例)

写法规则:

debug {subsystem} = {log-level}/{memory-level}
#for example
debug mds balancer = 1/20
写法 效果
debug ms = 5 单个值 → log level = 5,memory level = 5
debug ms = 1/5 斜杠分隔 → log level = 1,memory level = 5

完成排查后,要把各 subsystem 的值还原为默认值,或还原到适合日常运行的级别。

2.3 全量子系统默认级别表

下表逐项照抄官方 log-and-debug.rst 的 subsystem 表(Log Level = 输出日志级别,Memory Level = 内存日志级别)。

Subsystem Log Level Memory Level
default 0 5
lockdep 0 1
context 0 1
crush 1 1
mds 1 5
mds balancer 1 5
mds log 1 5
mds log expire 1 5
mds migrator 1 5
buffer 0 1
timer 0 1
filer 0 1
striper 0 1
objecter 0 1
rados 0 5
rbd 0 5
rbd mirror 0 5
rbd replay 0 5
rbd pwl 0 5
journaler 0 5
objectcacher 0 5
immutable obj cache 0 5
client 0 5
osd 1 5
optracker 0 5
objclass 0 5
filestore 1 3
journal 1 3
ms 0 5
mon 1 5
monc 0 10
paxos 1 5
tp 0 5
auth 1 5
crypto 1 5
finisher 1 1
reserver 1 1
heartbeatmap 1 5
perfcounter 1 5
rgw 1 5
rgw sync 1 5
rgw datacache 1 5
rgw access 1 5
rgw dbstore 1 5
rgw lifecycle 1 5
rgw notification 1 5
rgw bucket logging 1 5
javaclient 1 5
asok 1 5
throttle 1 1
refs 0 0
compressor 1 5
bluestore 1 5
bluefs 1 5
bdev 1 3
kstore 1 5
rocksdb 4 5
fuse 1 5
mgr 2 5
mgrc 1 5
dpdk 1 5
eventtrace 1 5
prioritycache 1 5
test 0 5
cephfs mirror 0 5
cephsqlite 0 5
seastore 0 5
seastore onode 0 5
seastore odata 0 5
seastore ompap 0 5
seastore tm 0 5
seastore t 0 5
seastore cleaner 0 5
seastore epm 0 5
seastore lba 0 5
seastore fixedkv tree 0 5
seastore cache 0 5
seastore journal 0 5
seastore device 0 5
seastore backref 0 5
alienstore 0 5
mclock 1 5
cyanstore 0 5
ceph exporter 1 5
memstore 1 5
trace 1 5

💡 补充(读法提示):写进 ceph.conf 或 ceph tell ... config set 时,subsystem 名里的空格要换成下划线。官方给的两个例子是:"debug mds balancer = 1/20" 这种 ini 写法,以及 "ceph tell osd.0 config set debug_osd 0/5" 这种 config 写法——前者空格,后者下划线。

2.4 运行时动态调整(三种方式)

方式一:ceph tell(走 MON,最常用)

ceph tell {daemon-type}.{daemon id or *} config set {name} {value}
  • {daemon-type} 取 osd、mon 或 mds
  • 指定具体 ID → 只作用于那一个守护进程;用 * 通配 → 作用于该类型的全部守护进程
# 只给 osd.0 开 debug
ceph tell osd.0 config set debug_osd 0/5

# 给所有 mon 开 debug(MON 排障常用)
ceph tell mon.* config set debug_mon 10/10

# 给指定 mon 开
ceph tell mon.FOO config set debug_mon 10/10

方式二:ceph daemon(连不上 MON 时的备选)

如果无法 bind 到 monitor,ceph tell 走不通,就登录到目标守护进程所在主机,用 ceph daemon 直接改那个守护进程的配置。

sudo ceph daemon osd.0 config set debug_osd 0/5

这正是 troubleshooting-mon.rst 里"无 quorum 时调整 debug 级别"用的同一种手法:ceph daemon mon.FOO config set debug_mon 10/10。

方式三:查看当前配置(改之前/之后都该看看)

# 登录有守护进程运行的主机
ceph daemon {daemon-name} config show | less
# 例
ceph daemon osd.0 config show | less

MON 侧等价命令:

ceph daemon mon.FOO config show
ceph daemon mon.FOO config get 'OPTION_NAME'

什么时候需要重启?

不需要。 troubleshooting-mon.rst 明确回答:"Do I need to restart a monitor to adjust debug levels? — No. It is not necessary to restart a Monitor when adjusting its debug levels."

还原默认值的做法:把上面的命令里的 10/10 换成 1/10 再跑一遍(官方原文即此写法)。

三种运行时方式对照表

方式 命令形态 是否需要 MON 可达 作用范围
ceph tell ceph tell osd.0 config set debug_osd 0/5 需要(命令走 MON) 单实例 / * 全类型
ceph daemon sudo ceph daemon osd.0 config set debug_osd 0/5 不需要(本地 asok) 单实例
启动前配置 写 ceph.conf 或中央配置库 —— 需重启/重载生效

2.5 开机时(Boot Time)设置

要在启动时就激活 debug 输出,必须把设置写进 Ceph 配置文件(或在中央配置库里设对应值):

  • 所有守护进程通用的 subsystem → 写在 [global] 段
  • 特定守护进程的 subsystem → 写在对应段([mon]、[osd]、[mds])

官方给的示例配置:

[global]
    debug_ms = 1/5

[mon]
    debug_mon = 20
    debug_paxos = 1/5
    debug_auth = 2

 [osd]
     debug_osd = 1/5
     debug_filestore = 1/5
     debug_journal = 1
     debug_monc = 5/20

[mds]
    debug_mds = 1
    debug_mds_balancer = 1

💡 补充:注意上面示例中 [osd] 段里的 debug_monc = 5/20 —— monc 是客户端侧与 MON 通信的子系统,默认值是 0/10(见 2.3 表),这里被提到了 5/20,属于"OSD 与 MON 通信异常"时的典型排查手段。

2.6 日志轮转加速(Accelerating Log Rotation)

场景:主机的日志文件系统快满了。

做法:改 /etc/logrotate.d/ceph,在 weekly 频率指令之后加一条 size 指令,提高轮转频率以防文件系统被撑满。为削平日志量尖峰,可以考虑把 weekly 改成 daily、把 rotate 改成 30。

步骤:

  1. 记下 /etc/logrotate.d/ceph 的默认设置:
rotate 7
weekly
compress
sharedscripts
  1. 加上 size 设置:
rotate 7
weekly
size 500M
compress
sharedscripts
  1. 打开当前用户的 crontab 编辑器:
crontab -e
  1. 加一条 cron 条目,让 cron 去检查 /etc/logrotate.d/ceph:
30 * * * * /usr/sbin/logrotate /etc/logrotate.d/ceph >/dev/null 2>&1

这样 /etc/logrotate.d/ceph 会被每 30 分钟检查一次(并可能轮转)。

项 官方默认值 / 建议值
rotate 默认 7,建议可改 30
频率 默认 weekly,建议可改 daily
size 官方示例中加的是 size 500M
其他 compress、sharedscripts
cron 周期 示例中为每 30 分钟

2.7 slow request 相关参数

⚠️ 文档未明确:log-and-debug.rst 页面本身没有列出 slow request 相关参数(该页的 confval 清单里只有通用日志项、MON 集群日志项、osd_debug_drop_ping_probability / osd_debug_drop_ping_duration、filestore_debug_omap_check、MDS 与 RGW 若干项)。slow request 的阈值参数出现在 troubleshooting-osd.rst。下面按源文原样列出,未出现在源文中的参数一律不臆造。

名称 默认值 含义
osd_op_complaint_time 30 秒 当 ceph-osd 响应请求过慢时,集群日志会收到报告"ops 耗时过长"的消息。这个告警阈值默认为 30 秒,可通过 osd_op_complaint_time 配置
osd_op_num_shards_hdd 5 mClock HDD 场景下的 OSD shard 数(mClock 排障章节给出的当前配置值)。调慢请求时改为 1
osd_op_num_threads_per_shard_hdd 1 每 shard 的线程数(同上,当前配置值)。调慢请求时改为 5
osd_debug_drop_ping_probability 文档未明确 log-and-debug.rst OSD 段列出的调试项(用于丢弃 ping 的概率),本册源文未给默认值
osd_debug_drop_ping_duration 文档未明确 log-and-debug.rst OSD 段列出的调试项(丢弃 ping 的持续时间),本册源文未给默认值

slow request 的两种日志形态(troubleshooting-osd.rst 原文):

Legacy 版本用 old requests:

osd.0 192.168.106.220:6800/18813 312 : [WRN] old request osd_op(client.5099.0:790 fatty_26485_object789 [write 0~4096] 2.5e54f643) v4 received at 2012-03-06 15:42:56.054801 currently waiting for sub ops

较新版本用 slow requests:

{date} {osd.num} [WRN] 1 slow requests, 1 included below; oldest blocked for > 30.005692 secs
{date} {osd.num}  [WRN] slow request 30.005692 seconds old, received at {date-time}: osd_op(client.4240.0:8 benchmark_data_ceph-1_39426_object7 [write 0~4194304] 0.69848840) v4 currently waiting for subops from [610]

2.8 日志与调试设置项清单(confval)

以下均为 log-and-debug.rst 列出的设置项。官方原文只列名字,未在本页给出默认值/描述——本册不对未给出内容做任何编造。

通用日志项:

设置项 默认值 说明
log_file 文档未明确 日志文件路径
log_max_new 文档未明确 新日志上限
log_max_recent 文档未明确 最近日志条数上限
log_to_file 文档未明确 是否写日志文件
log_to_stderr 文档未明确 是否写 stderr
err_to_stderr 文档未明确 错误是否写 stderr
log_to_syslog 文档未明确 是否写 syslog
err_to_syslog 文档未明确 错误是否写 syslog
log_flush_on_exit 文档未明确 退出时是否 flush 日志
clog_to_monitors 文档未明确 cluster log 是否发给 monitors
clog_to_syslog 文档未明确 cluster log 是否写 syslog

Monitors 集群日志项:

设置项 默认值 说明
mon_cluster_log_level 文档未明确 集群日志级别
mon_cluster_log_file 文档未明确 集群日志文件
mon_cluster_log_to_file 文档未明确 集群日志是否写文件
mon_cluster_log_to_syslog 文档未明确 集群日志是否写 syslog
mon_cluster_log_to_syslog_facility 文档未明确 syslog facility
mon_cluster_log_to_stderr 文档未明确 集群日志是否写 stderr
mon_cluster_log_to_journald 文档未明确 集群日志是否写 journald
mon_cluster_log_to_graylog 文档未明确 集群日志是否发 graylog
mon_cluster_log_to_graylog_host 文档未明确 graylog 主机
mon_cluster_log_to_graylog_port 文档未明确 graylog 端口
mon_log_max 文档未明确 MON 日志上限
mon_health_to_clog 文档未明确 健康状态是否进 cluster log
mon_health_to_clog_interval 文档未明确 间隔

Filestore:filestore_debug_omap_check(默认值:文档未明确)

MDS:mds_debug_scatterstat、mds_debug_frag、mds_debug_auth_pins、mds_debug_subtrees(默认值:文档未明确)

RADOS Gateway:rgw_log_nonexistent_bucket、rgw_log_object_name、rgw_log_object_name_utc、rgw_enable_ops_log、rgw_enable_usage_log、rgw_usage_log_flush_threshold、rgw_usage_log_tick_interval(默认值:文档未明确)

2.9 Valgrind

调试集群性能时,可能需要追查内存与线程问题。log-and-debug.rst 说明:

  • Valgrind 工具套件可用于检测某个特定守护进程、某一类守护进程、或整个集群的问题
  • 因为 Valgrind 计算开销大(computationally expensive),只在开发或调试 Ceph 时使用;其他时候用会拖慢系统
  • Valgrind 的消息输出到 stderr

2.10 debug 相关注意事项汇总

注意点 依据
开 debug 前先确认日志空间充足 冗余日志 >1GB/小时,OS 盘满则该节点停止工作
调级不需要重启守护进程 MON 篇明确"No"
只开有问题的那个组件,逐步按需扩展 官方推荐做法
问题定位完要还原默认值 "restore each subsystem's values to their defaults or to a level suitable for normal operations"
长期高日志量建议把一块盘挂到日志路径 /var/log/ceph/$cluster-$name.log
忘了降日志级别会拖慢 OSD OSD 篇"Logging Levels"节:OSD 会把宝贵系统资源耗在写冗长日志上
高日志级别会影响故障复现 debug 输出引入的延迟"sometimes hides race conditions"
MON 排障时推荐级别 debug_mon = 10、debug_ms = 1(求助前建议先设到这个级别再复现)
求助时不要一次甩几十万行 记下复现时刻的时间日期,据此截取日志片段

引自:Logging and Debugging


三、MON 排障(troubleshooting-mon.rst)

3.0 先建立一个正确预期

官方开篇:即便集群出现 monitor 相关问题,集群也不一定会挂。只要存活的 monitor 数量足够形成 quorum,集群就还能继续运行。

3.1 Initial Troubleshooting:四步排除法

第 1 步:确认 Monitor 在跑

确认 ceph-mon 进程在跑。有可能是升级之后还没重启 mon——检查这个低级疏漏能省下数小时的排查。

同时务必确认 ceph-mgr 守护进程也在跑。典型配置是每个 ceph-mon 配一个 ceph-mgr。

注:v1.12.5 之前的 Rook 不会运行超过两个 manager。

第 2 步:确认 Monitor 节点可达

某些罕见情况下,iptables 规则可能挡住了 Monitor 节点或 TCP 端口的访问——这些规则可能是早期压力测试或规则开发遗留的。排查方法:SSH 到每个 Monitor 节点,用 telnet 或 nc 等工具尝试连接其他每个 Monitor 节点的 tcp/3300 和 tcp/6789 端口。

第 3 步:确认 ceph status 能跑通并收到回包

  • 若 ceph status 能收到集群回包 → 集群起来了。Monitor 只在 quorum 已形成时才应答 status 请求。同时确认有一个或多个 mgr 守护进程被报为 running——健康的集群里 ceph status 会报所有 mgr 都在跑。
  • 若 收不到回包 → 很可能是 up 的 MON 数量不足以形成 quorum。
  • ceph -s 不带选项时会任意挑一个 Monitor 连。某些情况下用 -m 显式指定会有帮助:ceph status -m mymon1。

第 4 步:都不行?逐个 MON 单独问

即使没有形成 quorum,也可以单独联系每个 Monitor 并请求它的状态:

ceph tell mon.ID mon_status

对集群里每一个 Monitor 都跑一遍。另一种方式是 SSH 到每个 MON 节点,查询守护进程的 admin socket(见 3.2)。

3.2 使用 Monitor 的 admin socket

admin socket 是一个 Unix socket 文件,位于 monitor 的 run 目录,默认路径 /var/run/ceph/ceph-mon.ID.asok。默认位置可以被覆盖——集群守护进程跑在容器里时通常就在别处。

查找方法:查 ceph.conf 里的替代路径,或运行:

ceph-conf --name mon.ID --show-config-value admin_socket

关键行为:

  • admin socket 只在 Monitor 守护进程运行时可用
  • 每次 Monitor 正常关闭,admin socket 会被移除
  • 如果 Monitor 没在跑、但 asok 文件还在 → 很可能是非正常关闭
  • Monitor 没在跑时,无法使用 admin socket,ceph 命令很可能返回 Error 111: Connection Refused

访问方式:

# 方式一:通过 ceph tell
ceph tell mon.<id> mon_status

# 方式二:知道 asok 全路径时更直接
ceph --admin-daemon <full_path_to_asok_file> <command>

跑 ceph help 可以看到 admin socket 支持的所有命令,尤其注意这几个:config get、config show、mon stat、quorum_status。

3.3 理解 mon_status

注意:ceph tell mon.X mon_status 里的 X 不是让你原样输入,要替换成你自己集群的 MON ID。

示例输出:

{ "name": "c",
  "rank": 2,
  "state": "peon",
  "election_epoch": 38,
  "quorum": [
        1,
        2],
  "outside_quorum": [],
  "extra_probe_peers": [],
  "sync_provider": [],
  "monmap": { "epoch": 3,
      "fsid": "5c4e9d53-e2e1-478a-8061-f543f8be4cf8",
      "modified": "2013-10-30 04:12:01.945629",
      "created": "2013-10-29 14:14:41.914786",
      "mons": [
            { "rank": 0,
              "name": "a",
              "addr": "127.0.0.1:6789\/0"},
            { "rank": 1,
              "name": "b",
              "addr": "127.0.0.1:6790\/0"},
            { "rank": 2,
              "name": "c",
              "addr": "127.0.0.1:6795\/0"}]}}

这份输出说明:monmap 里有三个 monitor(a、b、c),quorum 只由两个组成,c 是 peon。

关键知识点(官方原文问答):

问题 答案
哪个 monitor 出 quorum 了? mon.a
怎么知道的? 因为 mon.a 的 rank 是 0,而rank 为 0 的 Monitor 按定义就是出 quorum 的。quorum 集合里是 1 和 2(这是 rank 不是名字),不含 0;按 monmap,rank 0 就是 mon.a
rank 怎么算出来的? 每当 monitor 被加入或移除时,rank 会(重新)计算。规则很简单:IP:PORT 组合越大,rank 越低。例中 127.0.0.1:6789(mon.a)数值上小于 127.0.0.1:6790(b)和 127.0.0.1:6795(c),所以 mon.a 的 rank 最高,即 rank 0

3.4 场景:集群有 quorum,但至少一个 Monitor 是 down 的

现象

$ ceph health detail
[snip]
mon.a (rank 0) addr 127.0.0.1:6789/0 is down (out of quorum)

原因

mon.a 处于 down / out of quorum 状态。

解决

  1. 确认 mon.a 在跑。
  2. 确认能从其他 Monitor 节点连到 mon.a 的节点,同时检查 TCP 端口。检查所有节点上的 iptables 和 nf_conntrack,确认没有 drop/reject 连接。

如果初始排查没解决,进一步调查:按 3.2 / 3.3 的方式,通过 admin socket 查这个有问题的 monitor 的 mon_status。

状态分流判断:

  • 如果 Monitor 真的不在 quorum 里 → 状态会是 probing、electing 或 synchronizing 之一
  • 如果状态是 leader 或 peon → 说明这个 Monitor 自认为在 quorum 里,但集群其余部分认为它不在
  • 处于 probing/electing/synchronizing 的 Monitor,有可能在你排查的过程中已经进 quorum 了 → 再跑一次 ceph status 确认。如果仍然不在,继续往下看。

子场景 A:状态 = probing

现象:ceph health detail 显示某 MON 状态为 probing。

原因:该 Monitor 还在寻找其他 Monitor。每个 Monitor 启动后都会在这个状态停留一段时间;连上了 monmap 里指定的其他 Monitor 之后,就退出 probing。停留时长取决于集群参数:

  • 单 monitor 集群(生产环境绝不要这样)→ probing 几乎瞬间过去
  • 多 monitor 集群 → 一直 probing 直到找到足够的 monitor 形成 quorum;三个 MON 挂了两个,剩下的那个会无限期停在 probing,直到你把其中一个拉起来

解决:

  1. 若 quorum 已建立,只要其他 MON 可达,该 MON 应该能很快找到它们。
  2. 若卡在 probing 且通信排查已做尽 → 可能是这个 Monitor 在用一个错误的地址去连其他 Monitor。用 mon_status 输出的 monmap,核对其余 Monitor 在 monmap 里的位置是否与网络中实际位置一致。
    • 不一致 → 见 3.5「恢复损坏的 monmap」
    • 一致 → 持续的 probing 可能与 monitor 节点间严重的时钟偏移有关 → 见 3.6
  3. 时钟也没问题 → 准备好系统日志,向 Ceph 社区求助(日志准备见 3.9)

子场景 B:状态 = electing

现象:ceph health detail 显示 MON 状态为 electing。

原因:该 monitor 正处于选举过程中。选举通常很快完成,但有时 monitor 会陷入所谓的 election storm(选举风暴)。选举风暴的存在可能暗示 monitor 节点之间存在时钟偏移。

解决:

  1. 查时钟 → 见 3.6
  2. 时钟是同步的 → 去邮件列表和 bug tracker 搜类似问题。electing 状态不太可能持续;在 Cuttlefish 之后的版本里,除了时钟偏移,没有别的明显原因能解释 electing 持续存在。
  3. 若要深挖持续 electing 的原因,可以在调查期间把这个有问题的 Monitor 置为 down——前提是存活的 Monitor 数量足够形成 quorum。

子场景 C:状态 = synchronizing

现象:ceph health detail 显示 MON 状态为 synchronizing。

原因:该 monitor 正在追赶集群其余部分,以便加入 quorum。同步耗时是集群 monitor store 大小、集群规模、集群状态的函数——更大、更 degraded 的集群通常会让 Monitor 在 synchronizing 停留更久(相对小而新的集群而言)。

解决:

  • 一般等待即可
  • 如果状态在 synchronizing → electing → synchronizing 之间来回跳,这说明有问题:集群状态推进(生成新 map)的速度太快,同步过程跟不上。这个问题在 Cuttlefish 之前更常见,之后的同步过程已被重构增强以避免这种动态。如果你在较新版本遇到,请到 Ceph bug tracker 报告(https://tracker.ceph.com),并提供日志佐证。

子场景 D:状态 = leader 或 peon(但集群认为它不在 quorum)

现象:ceph health detail 显示 MON 是 leader 或 peon。

原因:正常 HEALTH_OK 运行时,集群里一个 monitor 是 leader,其余都是 peon。所以这里的矛盾是"它自己觉得在 quorum,别人觉得不在"。官方判断:很可能是存在时钟偏移。

解决:

  1. 按 3.6 处理时钟
  2. 处理完仍然显示 leader/peon → 到 https://tracker.ceph.com 报告,并附日志

状态判定速查表

mon_status 的 state 含义 处置
probing 还在找其他 MON;启动时短暂正常;三 MON 挂二会永久停留 查连通性 → 核 monmap 地址 → 查时钟
electing 选举中;持续则可能是 election storm 查时钟 → 搜 ML/bug tracker → 可临时置 down
synchronizing 正在追赶数据以加入 quorum 等待;若与 electing 来回跳则报 bug
leader / peon 自认为在 quorum(正常态之一) 若与集群认知矛盾 → 查时钟 → 报 bug
—— Monitor 完全没在跑 见 3.1 第 1 步(升级后忘重启是常见原因)

3.5 恢复损坏/过期的 monmap

现象:某节点的 monmap 过期——该节点 down 了很久,期间集群的 Monitor 发生了变化。

一个正常 monmap 长这样:

epoch 3
fsid 5c4e9d53-e2e1-478a-8061-f543f8be4cf8
last_changed 2013-10-30 04:12:01.945629
created 2013-10-29 14:14:41.914786
0: 127.0.0.1:6789/0 mon.a
1: 127.0.0.1:6790/0 mon.b
2: 127.0.0.1:6795/0 mon.c

原因:节点长时间离线,期间集群 MON 成员变更。

解决:两种方案二选一。

方案 A:废弃这个 Monitor 并重新部署(Scrap and redeploy)

只有在你确定不会丢失该 Monitor 保存的信息时才这么做。确保你有其他状态良好的 Monitor,这样新 Monitor 才能与存活的 Monitor 同步。

⚠️ 记住:如果没有该 Monitor 内容的其他副本,销毁它会造成数据丢失。

方案 B:注入 monmap(Inject a monmap)

从集群里存活的 Monitor 取一份最新 monmap,注入到那个 monmap 损坏或缺失的 Monitor。

步骤:

  1. 取 monmap(二选一):
# a) 有 quorum:从 quorum 取
ceph mon getmap -o /tmp/monmap
# b) 没有 quorum:直接从已停止的 Monitor 抽取
ceph-mon -i ID-FOO --extract-monmap /tmp/monmap

(ID-FOO 是那个已停止 Monitor 的 ID)

  1. 停掉要注入的 Monitor:
service ceph -a stop mon.{mon-id}
  1. 注入 monmap:
ceph-mon -i ID --inject-monmap /tmp/monmap
  1. 启动该 Monitor。

⚠️ 警告:向 Monitor 注入 monmap 可能造成严重问题。注入会覆盖该 monitor 上现存的最新 monmap。小心!

3.6 时钟偏移(Clock Skews)

现象

mon.c addr 10.10.0.1:6789/0 clock skew 0.08235s > max 0.05s (latency 0.0045s)

(上例中 mon.c 被标记存在时钟偏移。)

原因

Paxos 一致性算法要求严格的时间同步,因此 quorum 内 monitor 之间的时钟偏移会严重影响 monitor 运作,由此产生的行为可能令人费解。

解决

在 monitor 节点上跑时钟同步工具,例如 Chrony 或传统的 ntpd。配置每个 monitor 节点,使 iburst 选项生效,并且每个 monitor 有多个 peer,包括:

  • 彼此(Each other)
  • 内部 NTP servers
  • 多个外部公共 pool servers

注:iburst 选项会发送 8 个包的突发(而不是通常的单个包),用于让两个 peer 进入初始同步状态。

进一步建议:

  • 建议把集群里所有节点都与内部和外部服务器同步,甚至也可以与你的 monitor 同步
  • 在裸金属上跑 NTP server:VM 虚拟化的时钟不适合稳定计时
  • 见 https://www.ntp.org
  • 你的组织可能已有高质量的内部 NTP server
  • NTP server 设备厂商举例(官方原文列出):Microsemi(原 Symmetricom)、EndRun、Netburner

时钟偏移 FAQ(官方原文)

问题 官方回答
最大可容忍时钟偏移是多少? 默认情况下,monitor 允许时钟漂移最大 0.05 秒(50 毫秒)
能调大吗? 能,但强烈建议不要。该值可通过 mon-clock-drift-allowed 选项配置,但改它几乎肯定是个坏主意。设这个上限是因为时钟偏移的 monitor 不可靠;当前默认值已被证明能在 monitor 遇到严重问题之前就告警,改它可能给 monitor 稳定性和整体集群健康带来不可预见的影响
怎么知道有没有时钟偏移? monitor 会通过集群状态 HEALTH_WARN 告警(输出形如上例)。Luminous 及以后还可以跑 ceph time-sync-status 检查。注意:lead monitor 通常 IP 数值最小,它永远显示 0——其他 monitor 报告的偏移是相对 lead monitor 的,不是相对某个外部参考源
有偏移了怎么办? 同步时钟。用 NTP 客户端可能有帮助。如果已经在用 NTP 客户端却仍有偏移问题,判断一下你用的 NTP server 是在远端网络上还是在你自己网络上——自建 NTP server 通常能缓解时钟偏移问题

3.7 客户端连不上 / 挂载失败(Client Can't Connect or Mount)

现象:客户端连不上集群,或挂载失败,伴随超时错误。

原因:某些操作系统安装工具会往 iptables 里加一条 REJECT 规则,该规则会拒绝除 ssh 之外所有尝试连接主机的客户端。如果 monitor 主机上有这样的 REJECT 规则,从其他节点连过来的客户端都会失败并超时。

典型规则形如:

REJECT all -- anywhere anywhere reject-with icmp-host-prohibited

解决:可能需要在 Ceph 主机上给 iptables 加规则,确保客户端能访问 Ceph monitor(默认端口 6789)和 Ceph OSD(默认端口 6800 到 7568)相关的 TCP 端口:

iptables -A INPUT -m multiport -p tcp -s {ip-address}/{netmask} --dports 6789,6800:7568 -j ACCEPT
组件 默认端口
Ceph Monitor 6789
Ceph OSD 6800 - 7568
MON 互联(troubleshooting-mon.rst 第 2 步要求连通性测试用) tcp/3300 与 tcp/6789

3.8 Monitor Store 故障

3.8.1 现象:store 损坏的症状

Ceph Monitor 把 Cluster Map 维护在一个 key-value store 里。如果 key-value store 损坏导致 Monitor 失败,Monitor 日志里可能出现以下错误消息之一:

Corruption: error in middle of record

或:

Corruption: 1 missing files; e.g.: /var/lib/ceph/mon/mon.foo/store.db/1234567.ldb

💡 补充:本册源文未明确说明 leveldb 与 rocksdb 的差异、以及各自的损坏判定方法;官方只给了上述两条通用 corruption 错误文本。若需区分 leveldb/rocksdb 特定行为,文档未明确。

3.8.2 解决方式一:用健康的 Monitor 恢复

现象:集群里还有存活的 Monitor。

原因:只有一个/少数 Monitor 的 store 损坏。

解决:把损坏的 Monitor **替换(replace)**为一个新 Monitor。新 Monitor 启动后会与健康的 peer 同步;完全同步之后就能服务客户端了。

3.8.3 解决方式二:用 OSD 恢复(即使所有 monitor 同时挂掉)

现象:所有 monitor 同时失败。

原因:官方建议部署至少三个(最好五个)Monitor,这样全部 MON 失效的可能性很小。但如果数据中心意外断电,而磁盘设置或文件系统设置配置不当导致底层文件系统失败,就可能把所有 monitor 一起干掉。此时可以用 OSD 里的数据来恢复 Monitor。

解决:以下脚本(官方原文)用于这种情况:

ms=/root/mon-store
mkdir $ms

# collect the cluster map from stopped OSDs
for host in $hosts; do
  rsync -avz $ms/. user@$host:$ms.remote
  rm -rf $ms
  ssh user@$host <<EOF
    for osd in /var/lib/ceph/osd/ceph-*; do
      ceph-objectstore-tool --data-path \$osd --no-mon-config --op update-mon-db --mon-store-path $ms.remote
    done
EOF
  rsync -avz user@$host:$ms.remote/. $ms
done

# rebuild the monitor store from the collected map, if the cluster does not
# use cephx authentication, we can skip the following steps to update the
# keyring with the caps, and there is no need to pass the "--keyring" option.
# i.e. just use "ceph-monstore-tool $ms rebuild" instead
ceph-authtool /path/to/admin.keyring -n mon. \
  --cap mon 'allow *'
ceph-authtool /path/to/admin.keyring -n client.admin \
  --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *'
# add one or more ceph-mgr's key to the keyring. in this case, an encoded key
# for mgr.x is added, you can find the encoded key in
# /etc/ceph/${cluster}.${mgr_name}.keyring on the machine where ceph-mgr is
# deployed
ceph-authtool /path/to/admin.keyring --add-key 'AQDN8kBe9PLWARAAZwxXMr+n85SBYbSlLcZnMA==' -n mgr.x \
  --cap mon 'allow profile mgr' --cap osd 'allow *' --cap mds 'allow *'
# If your monitors' ids are not sorted by ip address, please specify them in order.
# For example. if mon 'a' is 10.0.0.3, mon 'b' is 10.0.0.2, and mon 'c' is  10.0.0.4,
# please passing "--mon-ids b a c".
# In addition, if your monitors' ids are not single characters like 'a', 'b', 'c', please
# specify them in the command line by passing them as arguments of the "--mon-ids"
# option. if you are not sure, please check your ceph.conf to see if there is any
# sections named like '[mon.foo]'. don't pass the "--mon-ids" option, if you are
# using DNS SRV for looking up monitors.
ceph-monstore-tool $ms rebuild -- --keyring /path/to/admin.keyring --mon-ids alpha beta gamma

# make a backup of the corrupted store.db just in case!  repeat for
# all monitors.
mv /var/lib/ceph/mon/mon.foo/store.db /var/lib/ceph/mon/mon.foo/store.db.corrupted

# move rebuild store.db into place.  repeat for all monitors.
mv $ms/store.db /var/lib/ceph/mon/mon.foo/store.db
chown -R ceph:ceph /var/lib/ceph/mon/mon.foo/store.db

脚本四步(官方归纳):

  1. 从每个 OSD 主机收集 map
  2. 重建 store
  3. 用合适的 capabilities 填充 keyring 文件里的各个实体
  4. 用恢复出来的副本替换 mon.foo 上损坏的 store

脚本里的关键注意点(原文注释里的坑):

坑 说明
没开 cephx 可以跳过更新 keyring caps 的步骤,也不需要传 --keyring,直接 ceph-monstore-tool $ms rebuild 即可
mgr key 从哪找 /etc/ceph/${cluster}.${mgr_name}.keyring,在部署了 ceph-mgr 的那台机器上
MON ID 顺序 如果 monitor 的 id 不是按 IP 地址排序的,要显式按顺序指定(--mon-ids b a c)
非单字符 MON ID 也要用 --mon-ids 显式传;不确定就查 ceph.conf 里有没有 [mon.foo] 这样的段
用 DNS SRV 查 monitor 不要传 --mon-ids
备份 先 mv store.db store.db.corrupted 留底,每个 monitor 都要做
权限 放回去后 chown -R ceph:ceph

3.8.4 已知局限(Known limitations)

上述恢复工具无法恢复以下信息:

丢失项 说明
某些新增的 keyring 用 ceph auth add 添加的所有 OSD keyring 都能从 OSD 副本中恢复,client.admin keyring 由 ceph-monstore-tool 导入;但 MDS keyring 和所有其他 keyring 会缺失,可能需要手动重新添加
正在创建中的池 如果有 RADOS 池正处于创建过程中,这个状态会丢失。恢复工具假设所有池都已创建完成。如果恢复后某个"部分创建的池"里有 PG 卡在 unknown 状态,可以用 ceph osd force-create-pg 强制创建空 PG —— 这创建的是空 PG,只有你确定该池为空时才这么做
MDS Maps MDS maps 会丢失

3.9 Everything Failed! Now What? —— 求助与准备日志

求助渠道(MON 篇给出的)

务必先准备好日志,被要求时能立刻给出。

准备日志(Preparing your logs)

  1. 定位日志:MON 日志默认在 /var/log/ceph/ceph-mon.FOO.log*。若位置被改过:
ceph-conf --name mon.FOO --show-config-value log_file
  1. 提高 debug 级别:日志里的信息量由配置文件的 debug 级别决定。如果 Ceph 用的是默认 debug 级别,你的日志可能缺少帮助社区定位问题的重要信息。

    对有经验的排查者,官方建议只提高最相关子系统的级别(这对新手不容易)。大多数情况下,设置以下级别就足以记录到足够信息:

debug_mon = 10
debug_ms = 1

有时这些级别还不够,社区成员会要求你进一步调整这些或其他 debug 级别。无论如何,收到一些有用信息总比收到空日志强。

  1. 截取日志:只把与 MON 问题相关的日志片段发给社区。因为判断哪些相关可能不容易,社区也接受完整未删减的日志。但不要发几十万行且没有任何说明的日志。一个常识性做法:复现问题时记下当前的日期和时间,然后据此从日志里截取片段。

  2. 联系社区:邮件列表 / IRC / Slack,或在 tracker 上开新 issue:http://tracker.ceph.com/projects/ceph/issues/new

FAQ:调 debug 级别要重启 monitor 吗?

不需要。("No. It is not necessary to restart a Monitor when adjusting its debug levels.")

按有无 quorum 分两种手法:

# 有 quorum:注入到指定的 monitor
ceph tell mon.FOO config set debug_mon 10/10

# 有 quorum:一次性注入到所有 monitor
ceph tell mon.* config set debug_mon 10/10

# 没有 quorum:用该 monitor 的 admin socket 直接改
ceph daemon mon.FOO config set debug_mon 10/10

还原:把上面命令里的 10/10 换成 1/10 再跑一遍。

查看当前值:

ceph daemon mon.FOO config show
ceph daemon mon.FOO config get 'OPTION_NAME'

引自:Troubleshooting Monitors


四、OSD 排障(troubleshooting-osd.rst)

4.0 前提条件

排查 OSD 之前,先:

  1. 检查 monitor 与网络。跑 ceph health 或 ceph -s,显示 HEALTH_OK 说明 monitor 有 quorum。若 monitor 没有 quorum 或状态有错误,先解决 monitor 问题(见第三章)再继续。
  2. 检查网络。网络对 OSD 运行和性能影响显著。查主机侧丢包(dropped packets)和交换机侧 CRC 错误。

4.1 收集 OSD 数据

手段 命令 用途
日志 ls /var/log/ceph 日志不够详细就调级别(见第二章)
admin socket ls /var/run/ceph;ceph daemon {daemon-name} help;ceph daemon {socket-file} help 运行时信息
拓扑 ceph osd tree 集群拓扑(monitoring OSDs)
剩余空间 df -h(df --help 看选项) 文件系统剩余空间
I/O 统计 iostat -x 识别 I/O 相关问题
内核诊断 dmesg | grep scsi(配合 less/more/grep/tail) 内核诊断消息

4.2 停止 OSD 但不触发 rebalance

场景:需要对集群子集做维护,或处理影响某个故障域(例如一个 rack)的问题;停 OSD 时不想让 CRUSH 自动 rebalance。

做法(旧法,官方不推荐):

ceph osd set noout

⚠️ 官方警告:这更多是一个"思想实验",用来让读者理解故障域和 CRUSH 行为,并不是建议在 post-Luminous 世界里真的去跑 ceph osd set noout。当 OSD 回到 up 状态,rebalancing 会恢复,ceph osd set noout 引入的变更也会被撤销。

做法(Luminous 及以后,更安全):只给受影响的 OSD 打 flag:

ceph osd add-noout osd.0
ceph osd rm-noout  osd.0

也可以给整个 CRUSH bucket 打 flag。例如要停机给 prod-ceph-data1701 加内存:

ceph osd set-group noout prod-ceph-data1701

完整流程:

# 1) 打 flag
ceph osd set-group noout prod-ceph-data1701

# 2) 停 OSD 及该故障域内共置的其他 Ceph 服务
systemctl stop ceph\*.service ceph\*.target

# ... 做维护 ...

# 3) 重启 OSD 及其他停掉的守护进程
#    注:如果维护过程中主机重启过,则不需要手动起,会自动回来
sudo systemctl start ceph.target

# 4) 按需解除 flag
ceph osd unset noout
ceph osd unset-group noout prod-ceph-data1701

注:OSD 停止时,该 OSD 内的所有 placement group 会被标记为 degraded。 注:多数现代 Linux 发行版用 systemd;但某些系统(尤其较老的)可能需要等价的 service 或 start/stop 命令。

noout 相关命令对照

命令 作用范围 官方态度
ceph osd set noout / unset noout 全局 不推荐(post-Luminous)
ceph osd add-noout osd.N / rm-noout osd.N 单个 OSD 推荐(Luminous+)
ceph osd set-group noout <bucket> / unset-group noout <bucket> 整个 CRUSH bucket 推荐

4.3 OSD 起不来(An OSD Won't Start)

现象:集群已启动,但某个 OSD 起不来。

原因与解决(官方列出的检查清单,逐项对照):

检查项 现象/原因 解决
Configuration File 新安装后 OSD 起不来,可能是配置文件不合规范(例如写成了 hostname 而不是 host) 检查配置文件是否符合标准
Check Paths 配置里指定的路径与实际数据/元数据路径不一致(例如 journal、WAL、DB 的路径) 把 OSD 数据与元数据分开存放,以判断是配置文件写错还是实际挂载有问题;要把元数据放到单独的块设备上,就对驱动器做分区或 LVM,每个 OSD 分一个分区
Check Max Threadcount 某节点上 OSD 特别多,可能撞上了默认最大线程数(通常是 32,000);恢复期间尤其容易遇到 把最大线程数提到允许的上限 4194303:sysctl -w kernel.pid_max=4194303。若有效,必须固化:在 /etc/sysctl.d 下的文件或 /etc/sysctl.conf 里加 kernel.pid_max = 4194303
Check nf_conntrack 这个连接跟踪/限流系统给很多生产 Ceph 集群造成问题,且问题往往缓慢而隐蔽地浮现:随集群拓扑和客户端负载增长,神秘的间歇性连接失败和性能毛刺越来越多,尤其在一天中的某些时段 ① 先查 syslog 历史里的 "table full" 事件;② 用 sysctl 把 nf_conntrack_max 调到高得多的值;③ 提高 nf_conntrack_buckets,使 nf_conntrack_buckets × 8 = nf_conntrack_max(这可能需要 sysctl 之外的命令,例如 echo 131072 > /sys/module/nf_conntrack/parameters/hashsize);④ 另一条路是把相关内核模块加入黑名单彻底禁用处理——这招强力但脆弱:模块及列出顺序随内核版本而异,且即便黑名单了,iptables 和 docker 有时仍会激活连接跟踪;官方建议对这些 tunable 采用"设好就别管(set and forget)"策略,现代系统上不会消耗可观资源
Kernel Version 默认地,Ceph 使用的第三方工具可能有 bug 或与某些发行版/内核版本冲突(例如 Google 的 gperftools 和 TCMalloc) 确认内核版本与发行版,查阅 OS recommendations 与各 Ceph 版本的 release notes
Segment Fault 出现段错误 提高日志级别并重启有问题的守护进程;若段错误复现,去 bug tracker(https://tracker.ceph.com/projects/ceph/)和 dev、ceph-users 邮件列表归档(https://ceph.io/resources)搜是否有人遇到过。若确实是新的独有故障,发到 dev 邮件列表并提供:正在运行的 Ceph 具体版本、ceph.conf(敏感信息用 XXX 打码)、monitor status 输出、以及日志文件摘录

固化 kernel.pid_max:

kernel.pid_max = 4194303

4.4 OSD 挂了(An OSD Failed)

现象

ceph health
# HEALTH_WARN 1/3 in osds are down

ceph health detail
# HEALTH_WARN 1/3 in osds are down
# osd.0 is down since epoch 23, last address 192.168.106.220:6800/11080

或用:

ceph osd tree down

原因

OSD 失败意味着 ceph-osd 进程无响应或已死,相应 OSD 被标记 down。存活的 ceph-osd 守护进程会向 monitor 报告该 OSD 似乎是 down 的。只要有 1 个或多个 OSD 同时处于 in 和 down,就会触发这条健康告警。

解决(分因施治)

线索 处置
驱动器故障或其他阻止 ceph-osd 运行/重启的故障 /var/log/ceph 下该 OSD 的日志文件里应该有错误消息
ceph-osd 因心跳失败或 suicide timeout 错误停止 底层驱动器或文件系统可能无响应。查 dmesg 和 syslog 输出里的磁盘错误或内核错误。可能需要加参数(例如 dmesg -T 看人类可读时间戳)以免把旧错误误当新错误
一整台主机的 OSD 全 down 检查是否有网络错误或该主机的硬件问题
软件错误导致(例如断言失败或其他意外错误) 到 bug tracker、dev 邮件列表归档、ceph-users 邮件列表归档搜索;若没有明确的修复或已有 bug,向 ceph-devel 邮件列表报告

💡 补充:官方在"正常条件下"给出的最简处置是——重启 ceph-osd 守护进程,它会重新加入集群并进入 recovery("Under normal conditions, restarting a ceph-osd daemon will allow it to rejoin the cluster and recover.")。

4.5 磁盘满 / No Free Drive Space

现象

ceph health
# HEALTH_WARN 1 nearfull osd(s)

ceph health detail
# HEALTH_ERR 1 full osd(s); 1 backfillfull osd(s); 1 nearfull osd(s)
# osd.3 is full at 97%
# osd.4 is backfill full at 91%
# osd.2 is near full at 87%

原因

OSD 满时,Ceph 通过阻止新数据写入该 OSD 来防止数据丢失。在正常运行的集群里,当集群 OSD 和池接近某些"满"比率时,会触发健康检查。

三个关键阈值(默认值,务必记牢)

配置项 默认值 含义
mon_osd_full_ratio 0.95(容量 95%) 超过此点,客户端被阻止写入数据
mon_osd_backfillfull_ratio 0.90(容量 90%) 超过此点,backfill 不会启动
mon_osd_nearfull_ratio 0.85(容量 85%) 达到此点,触发 OSD_NEARFULL 健康检查

解决

  1. 查看 fullness:
ceph osd df     # 逐个 OSD 展示数据占用
ceph df         # 集群整体用量与池间分布

⚠️ 看 ceph df 输出时要特别关注最满的那几个 OSD,而不是 raw 空间使用百分比。只要一个离群 OSD 满了,写到这个 OSD 所属池的所有 I/O 都可能失败。ceph df 报告某池可用空间时,是按该池中最满的那个 OSD 来套算比率的。

  1. 拉平分布(两种途径):

    • 用 reweight-by-utilization 命令,逐步把数据从过满的 OSD 挪走、或挪到过空的 OSD
    • 在 Luminous 的较后修订版及以后,用 ceph-mgr 的 balancer 模块自动完成同样的事
  2. 调整阈值:

ceph osd set-nearfull-ratio <float[0.0-1.0]>
ceph osd set-full-ratio <float[0.0-1.0]>
ceph osd set-backfillfull-ratio <float[0.0-1.0]>
  1. 加容量:建议通过增加 OSD 来解决满集群问题——加新 OSD 让集群把数据重新分布到新可用存储上。
  2. 查浪费的空间:搜索 rados bench 遗留的孤儿数据(orphans)占用空间。
  3. Filestore 的极端手段:如果 legacy Filestore OSD 因为满了而无法启动,可以通过删除该满 OSD 上少量 placement group 目录来回收空间。

⚠️ 极其重要(官方原文加粗):如果你决定删除某个满 OSD 上的 PG 目录,绝对不要在另一个满 OSD 上删除同一个 PG 目录。否则你会丢数据。你必须在至少一个 OSD 上保留至少一份数据副本。删除 PG 目录是一种罕见且极端的干预手段,不可轻率进行。

为什么小集群容易满(官方解释):有时满集群问题是因为某个 OSD 失败引起的——可能是因为测试,也可能是因为集群小、非常满或不均衡。当某个 OSD 或节点持有集群数据的过高比例时,部件故障或自然增长就会导致 nearfull/full 比率被突破。在小集群上测试 Ceph 对 OSD 故障的韧性时,建议留出充裕的空闲磁盘空间,并考虑临时调低 OSD 的 full ratio、backfillfull ratio 和 nearfull ratio。

4.6 OSD 慢 / 无响应(OSDs are Slow/Unresponsive)

排查这个常见问题时,官方建议先排除其他可能,再深入 OSD 性能:确认网络正常、OSD 在跑、OSD 是否在限流 recovery 流量。

💡 补充(官方 tip):在 pre-Luminous 版本里,up 且 in 的 OSD 有时会不可用或很慢,是因为正在做 recovery 的 OSD 消耗了系统资源。较新版本提供了更好的 recovery 处理来避免这种现象。

下面逐项列出官方给出的可能成因与对应处置。

4.6.1 网络问题(Networking Issues)

现象:OSD 延迟、OSD flapping。

原因:作为分布式存储系统,Ceph 依赖网络完成 OSD peering 与复制、故障恢复、以及周期性心跳。

解决:确认 Ceph 进程及依赖进程已连接并在监听:

netstat -a | grep ceph
netstat -l | grep ceph
sudo netstat -p | grep ceph

查网络统计:

netstat -s

4.6.2 驱动器配置(Drive Configuration)

原因:一块 SAS 或 SATA 盘应该只放一个 OSD,而一块 NVMe 盘可以轻松放两个或更多。但如果其他进程共用这块盘,读写吞吐可能成为瓶颈。共用者包括:journals / metadata、操作系统、Ceph monitor、syslog 日志、其他 OSD、以及非 Ceph 进程。

解决要点:

  • 因为 Ceph 是在 journaling 之后才确认写(acknowledges writes),所以对 legacy FileStore OSD 而言,用快速 SSD 是加速响应时间的诱人选项(尤其在 XFS 或 ext4 上)
  • 相比之下,Btrfs 可以同时写和 journal(但不建议在生产部署中使用 Btrfs)
  • 给驱动器分区并不会改变其总吞吐或顺序读写上限。把 journal 放在单独分区可能略微改善吞吐,但放在单独的物理驱动器上更好

⚠️ 官方警告:Reef 不支持 FileStore。Reef 之后的版本也不支持 FileStore。 任何提到 FileStore 的信息只适用于 Quincy 及更早的 Ceph 版本。

4.6.3 坏扇区 / 碎片化磁盘(Bad Sectors / Fragmented Disk)

解决:检查驱动器的坏块、碎片及其他会导致性能显著下降的错误。有用的工具:dmesg、syslog 日志、以及 smartctl(在 smartmontools 包里)。

注:smartmontools 7.0 及以后提供 NVMe stat passthrough 和 JSON 输出。

4.6.4 Monitor 与 OSD 共置(Co-resident Monitors/OSDs)

原因:monitor 虽然相对轻量,但与 OSD 跑在同一主机上会导致性能问题:Monitor 会发起大量 fsync() 调用,这会干扰其他负载。当 monitor 与 OSD 共置在同一块存储驱动器上时,性能问题的风险尤其尖锐。此外,如果 monitor 跑在较老内核(pre-3.0)或没有 syncfs(2) syscall 的内核上,同一主机上跑的多个 OSD 可能提交过多请求,从而互相拖累性能——这有时会导致所谓的"the bursty writes"。

解决:避免 MON 与 OSD 共置,尤其避免共置在同一块盘上。

4.6.5 其他进程共置(Co-resident Processes)

原因:向 Ceph 写数据的进程(例如云方案、虚拟机)如果与 OSD 跑在同一硬件上,会导致显著的 OSD 延迟。

解决:官方一般不推荐让这类进程与 OSD 共置。推荐做法是:某些主机专门优化给 Ceph 用,其他主机跑其他进程。把 Ceph 操作与其他应用分离,既可能提升性能,也可能简化排障与维护。

这种在同一硬件上跑共置进程的做法有时被称为"convergence(融合)"。使用 Ceph 时,只有具备专业知识并经过考虑后才进行融合。

4.6.6 日志级别(Logging Levels)

原因:高日志级别会导致性能问题。运维人员有时为了追问题调高日志级别,事后忘记调回去。这种情况下,OSD 会把宝贵的系统资源消耗在往磁盘写无谓的冗长日志上。

解决:确实需要长期高日志级别的人,建议挂一块盘到默认日志路径(例如 /var/log/ceph/$cluster-$name.log)。

4.6.7 Recovery 限流(Recovery Throttling)

原因:取决于你的配置,Ceph 可能降低 recovery 速率以维持客户端或 OSD 性能,也可能提高 recovery 速率到影响客户端或 OSD 性能的程度。

解决:检查客户端或 OSD 是否正在做 recovery。

4.6.8 内核版本(Kernel Version)

原因:较老的内核可能缺少改善 Ceph 性能的更新。

解决:检查你正在跑的内核版本。

4.6.9 SyncFS 内核问题(Kernel Issues with SyncFS)

原因:老内核可能没有足够新的 glibc 来支撑 syncfs(2)。

解决:试着每台主机只跑一个 OSD,看性能是否改善。

4.6.10 文件系统问题(Filesystem Issues)

官方推荐:

场景 推荐 不推荐
post-Luminous 版本 用 BlueStore 后端部署集群 ——
pre-Luminous 版本,或有特殊理由用上一代 Filestore 后端 XFS Btrfs、ext4
  • 不推荐 Btrfs:它有很多吸引人的特性,但 bug 可能导致性能问题和虚假的 ENOSPC 错误
  • 不推荐 ext4(用于 Filestore OSD):xattr 限制会破坏对长对象名的支持,而 RGW 需要长对象名

4.6.11 内存不足(Insufficient RAM)

官方建议:每个 OSD 守护进程最少 4GB RAM,并建议从 6GB 向上取整到 8GB。

原因:正常运行时你可能注意到 ceph-osd 进程只用了其中一小部分,于是想把多余 RAM 给共置应用用,或者省着配每个节点的内存。但当 OSD 进入 recovery 时,内存占用会飙升。如果 recovery 期间可用内存不足,OSD 性能会大幅下降,守护进程甚至可能崩溃或被 Linux OOM Killer 杀掉。

4.6.12 Blocked Requests / Slow Requests

现象:ceph-osd 响应请求过慢时,集群日志会收到报告 ops 耗时过长的消息。告警阈值默认 30 秒,可通过 osd_op_complaint_time 配置(日志样例见 2.7)。

可能成因(官方清单):

  • 驱动器故障(查 dmesg 输出)
  • 内核文件系统 bug(查 dmesg 输出)
  • 集群过载(查系统负载、iostat 等)
  • ceph-osd 守护进程的 bug
  • OSD shard 配置欠佳(在带 mClock 调度器的 HDD 集群上)

可能的解决方案(官方清单):

  • 把 VM 从 Ceph 主机上挪走
  • 升级内核
  • 升级 Ceph
  • 重启 OSD
  • 更换故障或即将故障的部件
  • 覆盖 OSD shard 配置(在带 mClock 调度器的 HDD 集群上)——见 4.6.14

4.6.13 调试 Slow Requests:dump_historic_ops / dump_ops_in_flight

ceph daemon osd.<id> dump_historic_ops
ceph daemon osd.<id> dump_ops_in_flight

你会看到一组操作,以及每个操作经历过的事件列表。事件分四层:

来自 Messenger 层:

事件 含义
header_read messenger 首次开始从网络上读取该消息的时间
throttled messenger 尝试获取内存限流空间(memory throttle space)以把消息读入内存的时间
all_read messenger 从网络上读完该消息的时间
dispatched messenger 把消息交给 OSD 的时间
initiated 与 header_read 相同。两者同时存在是历史遗留的怪现象

来自 OSD 处理 ops 的过程:

事件 含义
queued_for_pg 该 op 已被放入其 PG 的处理队列
reached_pg PG 已开始执行该 op
waiting for \* 该 op 在等待某项其他工作完成后才能继续(例如新的 OSDMap;其目标对象的 scrubbing;某个 PG peering 的完成;均按消息中的说明)
started 该 op 已被接受为 OSD 应当执行的操作,现正在执行
waiting for subops from 该 op 已被发送给副本 OSD

来自 Filestore:

事件 含义
commit_queued_for_journal_write 该 op 已交给 FileStore
write_thread_in_journal_buffer 该 op 在 journal 的 buffer 中,等待被持久化(作为下一次磁盘写)
journaled_completion_queued 该 op 已落 journal 到磁盘,其回调已排队等待调用

数据交给底层存储之后的 OSD 事件:

事件 含义
op_commit 该 op 已被 primary OSD 提交(即写入 journal)
op_applied 该 op 已用 write() 写到后端 FS(即已在内存中 apply,但尚未 flush 到磁盘),在 primary 上
sub_op_applied 同 op_applied,但针对副本的 "subop"
sub_op_committed 同 op_commit,但针对副本的 subop(仅 EC 池)
sub_op_commit_rec/sub_op_apply_rec from <X> primary 收到上述事件时打的标记,针对某个具体副本(即 <X>)
commit_sent 已向客户端(或对 sub ops 而言是 primary OSD)发回响应

注:官方说这些事件有些看起来冗余,但它们跨越了内部代码的重要边界(比如跨锁把数据传递给新线程)。

4.6.14 mClock 调度器下的慢请求 / 慢恢复

适用前提(官方 note):这段排障只适用于满足以下条件的场景——HDD 集群、运行 mClock 调度器、且 OSD shard 配置为 osd_op_num_shards_hdd = 5 和 osd_op_num_threads_per_shard_hdd = 1。

现象:在规模较大的 HDD 集群上,启用 mClock 且出现多个 OSD 节点故障时,可能报告或观察到:

  • slow requests:并进一步表现为客户端 I/O 性能下降
  • slow background recoveries:恢复吞吐低于预期

排查步骤:

  1. 从 OSD 事件确认 slow requests 是否** predominantly 属于 queued_for_pg 类型**
  2. 确认报告出来的 recovery 速率是否显著低于按后台 recovery 服务的 QoS 配额所预期的速率

解决:若上述任一步成立,可应用以下处置。注意这是破坏性的,涉及 OSD 重启:

ceph config set osd osd_op_num_shards_hdd 1
ceph config set osd osd_op_num_threads_per_shard_hdd 5

上述配置不会立即生效,需要重启环境中的 OSD。为了把影响降到最低,OSD 可以采用精心错开(carefully staggered)的方式逐个重启。

引自:Troubleshooting OSDs

4.7 Flapping OSDs

现象:OSD 被反复且快速地标记 up 然后再 down。

原因(官方详解)

OSD 做 peering 和心跳检查时,会在集群(后端)网络可用时使用它。

上游社区传统上推荐分离的 public(前端)与 private(集群/后端/复制)网络,带来两点好处:

  1. 把(1)心跳流量与复制/恢复流量(private)和(2)客户端流量及 OSD↔MON 流量(public)隔离开,避免一股流量把另一股 DoS 掉而引发级联故障
  2. 为 public 和 private 流量都提供额外吞吐

但是:过去网络技术还在 100Mb/s ~ 1Gb/s 量级时,这种分离往往很关键;在今天的 10Gb/s、40Gb/s、25/50/100Gb/s 网络下,上述容量顾虑常常被削弱甚至消除。举例:如果你的 OSD 节点有两个网口,把一个专给 public、另一个专给 private,就意味着你没有路径冗余——这会削弱你承受网络维护和网络故障而不显著影响集群或客户端的能力。这种情况下,官方建议改为把两条链路都只用作 public 网络:配合 bonding(LACP)或等价路由(例如 FRR),你可以同时获得吞吐余量提升、容错、以及减少 OSD flapping 的好处。

flapping 的形成机制:当 private 网络(甚至单条主机链路)故障或降级、而 public 网络继续正常运行时,OSD 可能处理不好:OSD 会通过 public 网络互相向 monitor 报告对方 down,同时把自己标记 up;monitor 又(同样通过 public 网络)发出把受影响 OSD 标记为 down 的新集群 map;这些 OSD 又回复 monitor"I'm not dead yet!",然后循环往复。这个场景被称为 flapping,很难隔离和修复。如果没有 private 网络,这种恼人的动态就被避免了:OSD 一般是非 up 即 down,不会 flapping。

解决:临时冻结状态

如果有东西导致 OSD 'flap',你可以强制 monitor 停止 flapping,临时冻结它们的状态:

ceph osd set noup      # prevent OSDs from getting marked up
ceph osd set nodown    # prevent OSDs from getting marked down

这些 flag 记录在 osdmap 里:

ceph osd dump | grep flags
# flags no-up,no-down

清除:

ceph osd unset noup
ceph osd unset nodown

四个 flag 的语义

flag 作用
noup 阻止 OSD 被 mark up
nodown 阻止 OSD 被 mark down
noin 阻止正在启动的 OSD 被 mark in(即被分配数据)
noout 保护 OSD 不被最终 mark out(无论 mon_osd_down_out_interval 当前值是多少)

注:noup、noout、nodown 是"临时"的——flag 清除后,它们原本阻止的动作很快就能发生。但 noin 会阻止 OSD 在启动时被 mark in,并且在 flag 生效期间启动的任何守护进程都会保持那种状态。

注:flapping 的成因与影响,可以通过谨慎调整 mon_osd_down_out_subtree_limit、mon_osd_reporter_subtree_level 和 mon_osd_min_down_reporters 得到一定缓解。最优设置的推导取决于集群规模、拓扑和所用 Ceph 版本,这些因素之间的相互作用很微妙,超出了本文档的范围。

引自:Troubleshooting OSDs


五、PG 排障(troubleshooting-pg.rst)

5.1 PG 永远不 clean(Placement Groups Never Get Clean)

现象:PG 停留在 active、active+remapped 或 active+degraded 状态,始终达不到 active+clean。

原因:可能说明 Ceph 集群配置有问题。

解决:复查 Pool, PG and CRUSH Config Reference 里的设置并做适当调整。一般规则:运行集群时使用多于一个 OSD,并且池 size 大于两个对象副本。

子场景:单节点集群(One Node Cluster)

现象:单节点上 PG 无法 clean。

原因/官方立场:Ceph 不再提供在单节点上运维的文档。为分布式计算设计的系统按定义就不该跑在单节点上。在包含 Ceph 守护进程的单节点上挂载客户端内核模块,可能由于 Linux 内核本身的问题导致死锁(除非用 VM 作为客户端)。尽管有这些限制,你仍然可以用单节点配置来试验 Ceph。

解决:要在单节点上创建集群,必须在创建 monitor 和 OSD 之前,把 osd_crush_chooseleaf_type 从默认的 1(含义 host/node)改为 0(含义 osd)。这告诉 Ceph:允许把一个 OSD 的 PG 与同一主机上另一个 OSD 的 PG 放在一起。如果你在搭单节点集群而 osd_crush_chooseleaf_type 大于 0,Ceph 会尝试把一个 OSD 的 PG 与另一个 OSD 的 PG 放在另一个 node、chassis、rack、row 或 datacenter(取决于设置值)。

tip:不要把内核客户端直接挂载在 Ceph 存储集群所在的同一节点上,可能产生内核冲突。但可以在单节点上的虚拟机里挂载内核客户端。

补充(原文):如果你用单块磁盘创建 OSD,必须先手动创建数据目录。

子场景:OSD 数少于副本数(Fewer OSDs than Replicas)

现象:两个 OSD 处于 up 且 in,但 PG 不在 active + clean。

原因:可能 osd_pool_default_size 设得大于 2。

解决(三条路):

目标 做法
想以两个副本在 active + degraded 下运行 把 osd_pool_default_min_size 设为 2,这样就能在 active + degraded 状态下写对象
想只有两份存储副本(原始 + 一份副本) 把 osd_pool_default_size 设为 2,这样集群应能达到 active + clean

注:这些改动可以在集群运行时做。 如果你是在 ceph.conf 里改的,可能需要重启集群。

子场景:Pool Size = 1

现象/原因:若 osd_pool_default_size 设为 1,你就只有一份对象副本。OSD 依赖其他 OSD 来告诉它"你该有哪些对象";如果只有一个 OSD 有某对象的副本、没有第二份,就没有第二个 OSD 来告诉第一个 OSD 它该有这个副本。

解决:对映射到该 OSD 的每一个 PG(用 ceph pg dump 看),强制让这个 OSD 注意到它需要的 PG:

ceph osd force-create-pg <pgid>

子场景:CRUSH Map 错误

现象:集群里有 PG 不 clean。

原因:可能是你的 CRUSH map 有错。

解决:检查 CRUSH map(第五章末还有 EC 池相关的 CRUSH 排查,见 5.8)。

5.2 Stuck Placement Groups(卡住的 PG)

背景:组件故障后 PG 进入 "degraded" 或 "peering" 是正常的,通常反映故障恢复流程的正常推进。但长时间停留在这些状态之一,可能预示更大的问题。因此 Ceph Monitor 会在 PG "stuck" 于非最优状态时告警。具体检查三类:

类别 含义
inactive 该 PG 太久没有 active(即它一直无法服务读写请求)
unclean 该 PG 太久没有 clean(即它一直无法从之前的故障中完全恢复)
stale 该 PG 的状态一直没有被某个 ceph-osd 更新。这表明存储该 PG 的所有节点可能都 down 了

列出来:

ceph pg dump_stuck stale
ceph pg dump_stuck inactive
ceph pg dump_stuck unclean

三类 stuck 的归因(官方):

Stuck 类型 通常说明
stale 关键的 ceph-osd 守护进程没在跑
inactive peering 问题(见 5.3)
unclean 有东西阻止恢复完成,可能是 unfound objects(见 5.4)

5.3 PG Down —— Peering 失败(Placement Group Down - Peering Failure)

现象

ceph health detail
# HEALTH_ERR 7 pgs degraded; 12 pgs down; 12 pgs peering; 1 pgs recovering; 6 pgs stuck unclean; 114/3300 degraded (3.455%); 1/3 in osds are down
# ...
# pg 0.5 is down+peering
# pg 1.4 is down+peering
# ...
# osd.1 is down since epoch 69, last address 192.168.106.220:6801/8651

原因:某些情况下 ceph-osd 的 peering 过程会出问题,导致 PG 无法变为 active 和可用。

解决

  1. 查清 PG 为何被标记 down:
ceph pg 0.5 query
{ "state": "down+peering",
  ...
  "recovery_state": [
       { "name": "Started\/Primary\/Peering\/GetInfo",
         "enter_time": "2012-03-06 14:40:16.169679",
         "requested_info_from": []},
       { "name": "Started\/Primary\/Peering",
         "enter_time": "2012-03-06 14:40:16.169659",
         "probing_osds": [
               0,
               1],
         "blocked": "peering is blocked due to down osds",
         "down_osds_we_would_probe": [
               1],
         "peering_blocked_by": [
               { "osd": 1,
                 "current_lost_at": 0,
                 "comment": "starting or marking this osd lost may let us proceed"}]},
       { "name": "Started",
         "enter_time": "2012-03-06 14:40:16.169513"}
   ]
}

recovery_state 段告诉我们:peering 因为 ceph-osd 守护进程 down 而被阻塞,具体是 osd.1。

  1. 处置(两条路):

    • 好路:把那个 ceph-osd 拉起来,recovery 就会继续。
    • 坏路(最后手段):如果 osd.1 发生了灾难性故障(例如磁盘坏了),可以告知集群该 OSD 已 lost,让集群尽力而为。
ceph osd lost 1

Recovery 会继续。

⚠️ 极其重要(官方原文):告知集群某个 OSD 已 lost 是危险的,因为集群无法保证其他数据副本是一致且最新的。

5.4 Unfound Objects

现象

ceph health detail
# HEALTH_WARN 1 pgs degraded; 78/3778 unfound (2.065%)
# pg 2.4 is active+degraded, 78 unfound

原因:这说明存储集群知道某些对象(或已有对象的更新副本)存在,但没能找到它们的副本。

官方给的成因示例(数据在 OSD "1" 和 "2" 上的两副本 PG):

  1. 1 挂了
  2. 2 独自处理了一些写
  3. 1 起来了
  4. 1 和 2 重新 peer,1 上缺失的对象排队等待恢复
  5. 在新对象被复制过去之前,2 挂了

此时:1 知道这些对象存在,但没有任何存活的 ceph-osd 持有这些对象的副本。这种情况下,对这些对象的 IO 会阻塞,集群会期待故障节点尽快回来——这被认为比对用户返回 IO 错误更好。

注:上面这个情形正是在复制池上设 size=2、在纠删码池上设 m=1 会有丢数据风险的原因之一。

解决

第 1 步:列出 unfound 对象

ceph pg 2.4 list_unfound [starting offset, in json]
{
  "num_missing": 1,
  "num_unfound": 1,
  "objects": [
      {
          "oid": {
              "oid": "object",
              "key": "",
              "snapid": -2,
              "hash": 2249616407,
              "max": 0,
              "pool": 2,
              "namespace": ""
          },
          "need": "43'251",
          "have": "0'0",
          "flags": "none",
          "clean_regions": "clean_offsets: [], clean_omap: 0, new_object: 1",
          "locations": [
              "0(3)",
              "4(2)"
          ]
      }
  ],
  "state": "NotRecovering",
  "available_might_have_unfound": true,
  "might_have_unfound": [
      {
          "osd": "2(4)",
          "status": "osd is down"
      }
  ],
  "more": false
}
  • 如果一次列不完(对象太多),more 字段会是 true,你可以继续查询更多(官方原话: eventually the command line tool will hide this from you, but not yet)
  • 在列表末尾(在 more: false 之前),当 available_might_have_unfound 为 true 时会给出 might_have_unfound。这等价于 ceph pg #.# query 的输出,因此不必再直接用 query。它的行为与 query 的描述一致,唯一区别是状态为 already probed 的 OSD 会被忽略

第 2 步:用 query 看可能的位置(可选)

ceph pg 2.4 query
"recovery_state": [
     { "name": "Started\/Primary\/Active",
       "enter_time": "2012-03-06 15:15:46.713212",
       "might_have_unfound": [
             { "osd": 1,
               "status": "osd is down"}]},

上例中,集群知道 osd.1 可能有数据,但它 down 了。

might_have_unfound 里 OSD 状态的全部可能取值:

  • already probed
  • querying
  • OSD is down
  • not queried (yet)

有时集群查询可能位置只是需要一些时间。

第 3 步:注意"可能有数据但没被列出"的位置

官方提示:有可能存在其他未被列出的、对象可能存在的位置。例如:某个 OSD 被停掉并移出集群,然后集群完全恢复,随后又通过一系列故障导致集群出现 unfound 对象——此时集群会忽略那个已被移除的 OSD。(不过这个场景不太可能。)

第 4 步:万不得已,放弃丢失的对象(回滚 / 删除)

如果所有可能位置都查过了、对象仍然丢失,你可能不得不放弃这些丢失的对象。只有当发生了异常组合的故障、让集群在写操作本身被恢复之前就得知了这些写操作时,才会出现这种情况。

ceph pg 2.5 mark_unfound_lost revert|delete
选项 行为 限制
delete 让集群彻底忘记这些对象 无
revert 回滚到该对象的上一个版本,或者(如果它是个新对象)彻底忘记它 对纠删码池不可用。且要谨慎使用——它可能让那些预期该对象存在的应用产生困惑

5.5 Homeless Placement Groups(无家可归的 PG / stale)

现象

ceph health
# HEALTH_WARN 24 pgs stale; 3/300 in osds are down

原因:有可能持有某个 PG 副本的所有 OSD 都失败了。这时,包含这些 PG 的那部分对象存储变为不可用,monitor 收不到这些 PG 的状态更新。Monitor 会把主 OSD 已失败的 PG 标记为 stale。

解决

  1. 找出哪些 PG 是 stale、以及最后存储它们的 OSD 是哪些:
ceph health detail
# HEALTH_WARN 24 pgs stale; 3/300 in osds are down
# ...
# pg 2.5 is stuck stale+active+remapped, last acting [2,0]
# ...
# osd.10 is down since epoch 23, last address 192.168.106.220:6800/11080
# osd.11 is down since epoch 13, last address 192.168.106.220:6803/11539
# osd.12 is down since epoch 24, last address 192.168.106.220:6806/11861
  1. 上例表示 PG 2.5 最后是由 osd.0 和 osd.2 管理的 → 重启这些 OSD,让集群恢复该 PG。

5.6 只有少数 OSD 收到数据(Only a Few OSDs Receive Data)

现象:集群里只有少数节点在接收数据。

原因:检查该池的 PG 数量。因为 PG 到 OSD 的映射涉及"集群 PG 数 ÷ 集群 OSD 数"这个除法运算,少量 PG(即这个运算的余数)有时不会被分布到整个集群。

解决:创建一个 PG 数量是 OSD 数量的倍数的池。详见 Placement Groups 文档;改默认值见 Pool, PG, and CRUSH Config Reference。

5.7 无法写数据(Can't Write Data)

现象:集群是 up 的,但某些 OSD 是 down 的,且你无法写入数据。

原因:确认池中运行的 OSD 数量是否达到最小值。如果没有达到池的最小 OSD 数,Ceph 不会允许你往里写数据,因为无法保证 Ceph 能复制你的数据。

解决:参见 osd_pool_default_min_size(Pool, PG, and CRUSH Config Reference)。

5.8 PG Inconsistent

现象:ceph health detail 返回 active + clean + inconsistent。

ceph health detail
# HEALTH_ERR 1 pgs inconsistent; 2 scrub errors
# pg 0.6 is active+clean+inconsistent, acting [0,1,2]
# 2 scrub errors

原因:这可能表示 scrubbing 过程中出现错误。

解决

第 1 步:找出 inconsistent 的 PG

ceph health detail

或者用更适合程序化处理的方式:

rados list-inconsistent-pg rbd
# ["0.6"]

第 2 步:找出 inconsistent 的对象

rados list-inconsistent-obj 0.6 --format=json-pretty
{
    "epoch": 14,
    "inconsistents": [
        {
            "object": {
                "name": "foo",
                "nspace": "",
                "locator": "",
                "snap": "head",
                "version": 1
            },
            "errors": [
                "data_digest_mismatch",
                "size_mismatch"
            ],
            "union_shard_errors": [
                "data_digest_mismatch_info",
                "size_mismatch_info"
            ],
            "selected_object_info": "0:602f83fe:::foo:head(16'1 client.4110.0:1 dirty|data_digest|omap_digest s 968 uv 1 dd e978e67f od ffffffff alloc_hint [0 0 0])",
            "shards": [
                {
                    "osd": 0,
                    "errors": [],
                    "size": 968,
                    "omap_digest": "0xffffffff",
                    "data_digest": "0xe978e67f"
                },
                {
                    "osd": 1,
                    "errors": [],
                    "size": 968,
                    "omap_digest": "0xffffffff",
                    "data_digest": "0xe978e67f"
                },
                {
                    "osd": 2,
                    "errors": [
                        "data_digest_mismatch_info",
                        "size_mismatch_info"
                    ],
                    "size": 0,
                    "omap_digest": "0xffffffff",
                    "data_digest": "0xffffffff"
                }
            ]
        }
    ]
}

第 3 步:读懂输出(官方逐项解释)

上例中:唯一 inconsistent 的对象名为 foo,其 head 存在不一致。不一致分两类:

  1. errors:这些错误表示 shard 之间的不一致,但不指明哪个(些)shard 是坏的。要定位问题,去查 shards 数组里的 errors(如果有的话)。

    • data_digest_mismatch:从 OSD.2 读出的副本 digest 与从 OSD.0、OSD.1 读出的不同
    • size_mismatch:从 OSD.2 读出的副本 size 是 0,而 OSD.0 和 OSD.1 报的是 968
  2. union_shard_errors:shards 数组中所有 shard 专属 errors 的并集。这些 errors 是设在有问题的那个 shard 上的,包括 read_error 等类似错误。以 oi 结尾的 errors 表示与 selected_object_info 做了比较。检查 shards 数组来确定哪个 shard 有哪些错误。

    • data_digest_mismatch_info:object-info 里存的 digest 不是 0xffffffff,而 0xffffffff 是从 OSD.2 读出的那个 shard 算出来的
    • size_mismatch_info:object-info 里存的 size 与从 OSD.2 读出的 size 不同(后者是 0)

⚠️ 警告:如果某个 shard 的 errors 属性里列出了 read_error,那么这个不一致很可能源于物理存储错误。这种情况下,去检查该 OSD 使用的存储——在尝试修盘之前,先看 dmesg 和 smartctl 的输出。

第 4 步:修复

ceph pg repair {placement-group-ID}

例如:

ceph pg repair 1.4

⚠️ 官方警告:这条命令会用 "authoritative"(权威)副本覆盖"坏"副本。大多数情况下,Ceph 能依据一些预定义准则从所有可用副本中选出权威副本。但这并非每次都奏效:例如可能存储的数据 digest 缺失,这意味着 Ceph 在选权威副本时会忽略计算出的 digest。请知晓这一点,谨慎使用该命令。

注:PG ID 形如 N.xxxxx,其中 N 是该 PG 所属池的编号。 ceph osd listpools 和 ceph osd dump | grep pool 都能返回池编号列表。

周期性出现 active + clean + inconsistent 且与时钟相关时:如果由于时钟偏移而周期性收到该状态,考虑把你 monitor 主机上的 NTP 守护进程配置为 peers。参见 The Network Time Protocol 与 Ceph Clock Settings。

关于 PG Repair 的更多说明(More Information on PG Repair)

机制:Ceph 存储并更新集群中对象的校验和(checksums)。对某 PG 做 scrub 时,lead OSD 会尝试从其副本中选出一份权威副本——只有一种可能情况是一致的。做 deep scrub 后,Ceph 会计算从磁盘读出的每个对象的校验和,并与之前记录的校验和比较;若不匹配,就视为不一致。在复制池中,任何对象副本的校验和与权威副本的校验和不匹配,就意味着存在不一致;发现这些不一致会导致 PG 状态被设为 inconsistent。

pg repair 能做什么:

  • 发现不一致 PG 时,尝试用权威副本的 digest 覆盖不一致副本的 digest
  • 在复制池中发现不一致副本时,把该不一致副本标记为 missing
  • 在复制池中,恢复(recovery)超出 pg repair 的范围

自动修复:在纠删码池和 BlueStore 池中,如果 osd_scrub_auto_repair(默认 false)被设为 true,且发现的错误不超过 osd_scrub_auto_repair_num_errors(默认 5) 个,Ceph 会自动执行修复。

配置项 默认值 含义
osd_scrub_auto_repair false 设为 true 时,EC 池与 BlueStore 池在错误数不超阈值时自动修复
osd_scrub_auto_repair_num_errors 5 自动修复允许的最大错误数

pg repair 不能做什么 / 注意事项:

  • pg repair 命令不能解决所有问题。发现 PG 包含不一致时,Ceph 不会自动修复 PG。
  • RADOS 对象或 omap 的校验和不总是可用。校验和是增量计算的:如果一个复制对象被非顺序(non-sequentially)更新,更新涉及的写操作会改变该对象并使其校验和失效;而重算校验和时不会读取整个对象。
  • pg repair 在没有校验和可用时也能做修复(如 Filestore 的情况)。使用复制型 Filestore 池的用户可能更偏好手动修复,而不是 ceph pg repair。
  • 这段内容适用于 Filestore,不适用于 BlueStore——BlueStore 有自己的内部校验和。
  • matched-record checksum 与 calculated checksum 都无法证明某个具体副本确实是权威的。如果没有可用的校验和,pg repair 会倾向于 primary 上的数据,但这可能并不是那个未损坏的副本。由于存在这种不确定性,发现不一致时需要人工介入,这种介入有时会用到 ceph-objectstore-tool。

PG Repair Walkthrough

官方给出的外部链接(原文照录):

https://ceph.io/geen-categorie/ceph-manually-repair-object/ - This page contains a walkthrough of the repair of a PG. It is recommended reading if you want to repair a PG but have never done so.

5.9 纠删码 PG 不 active+clean(Erasure Coded PGs are not active+clean)

现象:CRUSH 找不到足够的 OSD 映射到某个 PG 时,该位置会显示 2147483647,即 ITEM_NONE 或 no OSD found。

[2,1,6,0,5,8,2147483647,7,4]

下面分三种成因。

5.9.1 OSD 不够(Not enough OSDs)

现象:集群只有 8 个 OSD,而纠删码池需要 9 个 OSD → 显示 "Not enough OSDs"。

解决:二选一

# 方案一:另建一个需要更少 OSD 的纠删码池
ceph osd erasure-code-profile set myprofile k=5 m=3
ceph osd pool create erasurepool erasure myprofile
方案二:加新 OSD,PG 会自动使用它们

5.9.2 CRUSH 约束无法满足(CRUSH constraints cannot be satisfied)

现象:集群 OSD 数量够,但 CRUSH rule 施加了无法满足的约束。例如:10 个 OSD 分布在 2 台主机上,而 CRUSH rule 要求同一 PG 内不能有两个 OSD 来自同一主机 → 映射可能失败,因为只能找到 2 个 OSD。

排查:dump 出这条 rule 看约束:

ceph osd crush rule ls
# [
#     "replicated_rule",
#     "erasurepool"]
# $ ceph osd crush rule dump erasurepool
# { "rule_id": 1,
#   "rule_name": "erasurepool",
#   "type": 3,
#   "steps": [
#         { "op": "take",
#           "item": -1,
#           "item_name": "default"},
#         { "op": "chooseleaf_indep",
#           "num": 0,
#           "type": "host"},
#         { "op": "emit"}]}

解决:新建一个允许 PG 内 OSD 位于同一 host 的池:

ceph osd erasure-code-profile set myprofile crush-failure-domain=osd
ceph osd pool create erasurepool erasure myprofile

5.9.3 CRUSH 过早放弃(CRUSH gives up too soon)

现象:集群 OSD 数刚好够映射 PG(例如总共 9 个 OSD,而纠删码池每 PG 需要 9 个 OSD),CRUSH 可能在找到映射之前就放弃了。

解决(三条路):

  1. 降低纠删码池要求,让每 PG 用更少的 OSD —— 这需要另建一个池,因为 erasure code profile 不能动态修改
  2. 往集群加更多 OSD —— 这不需要修改纠删码池,PG 会自动变 clean
  3. 用手工 CRUSH rule,让它多试几次以找到好的映射 —— 可以对已有的 CRUSH rule 通过设置 set_choose_tries 为大于默认值的值来修改

验证与实施(全部离线进行,不碰集群)

第 1 步:先验证问题——从集群导出 crushmap 后用 crushtool 测试。这确保你的实验不会修改 Ceph 集群,只作用于本地文件:

ceph osd crush rule dump erasurepool
# { "rule_id": 1,
#   "rule_name": "erasurepool",
#   "type": 3,
#   "steps": [
#         { "op": "take",
#           "item": -1,
#           "item_name": "default"},
#         { "op": "chooseleaf_indep",
#           "num": 0,
#           "type": "host"},
#         { "op": "emit"}]}
ceph osd getcrushmap > crush.map
# got crush map from osdmap epoch 13
crushtool -i crush.map --test --show-bad-mappings \
   --rule 1 \
   --num-rep 9 \
   --min-x 1 --max-x $((1024 * 1024))
# bad mapping rule 8 x 43 num_rep 9 result [3,2,7,1,2147483647,8,5,6,0]
# bad mapping rule 8 x 79 num_rep 9 result [6,0,2,1,4,7,2147483647,5,8]
# bad mapping rule 8 x 173 num_rep 9 result [0,4,6,8,2,1,3,7,2147483647]

参数说明:

  • --num-rep:纠删码 CRUSH rule 需要的 OSD 数量
  • --rule:ceph osd crush rule dump 显示的 rule_id 字段值
  • 该测试会尝试映射 一百万个值(本例中由 [--min-x,--max-x] 定义的范围),必须至少显示一个 bad mapping。
  • 如果输出为空,说明所有映射都成功了,你可以确信集群的问题不是由 bad mappings 引起的。

第 2 步:反编译 CRUSH map,以便编辑 CRUSH rule:

crushtool --decompile crush.map > crush.txt

第 3 步:往 rule 里加一行:

step set_choose_tries 100

加完后 crush.txt 的相关部分形如:

rule erasurepool {
        id 1
        type erasure
        step set_chooseleaf_tries 5
        step set_choose_tries 100
        step take default
        step chooseleaf indep 0 type host
        step emit
}

第 4 步:重新编译并重新测试:

crushtool --compile crush.txt -o better-crush.map

第 5 步:所有映射都成功后,用 --show-choose-tries 显示"找到全部映射所需尝试次数"的直方图:

crushtool -i better-crush.map --test --show-bad-mappings \
 --show-choose-tries \
 --rule 1 \
 --num-rep 9 \
 --min-x 1 --max-x $((1024 * 1024))
# ...
# 11:        42
# 12:        44
# 13:        54
# ...
# 47:         1
# 48:         0
# ...
# 102:         0
# 103:         1
# 104:         0
# ...

读法:映射 42 个 PG 花了 11 次尝试,映射 44 个 PG 花了 12 次尝试,依此类推。尝试次数的最大值,就是能避免 bad mappings 的 set_choose_tries 最小值(上例中是 103,因为没有任何 PG 花了超过 103 次才被映射)。

引自:Troubleshooting PGs


六、CPU 性能剖析(cpu-profiling.rst)

6.0 前提

如果你是从源码构建 Ceph、并且为了配合 oprofile 而编译的,就可以剖析 Ceph 的 CPU 占用。详见 Installing Oprofile。

oprofile 项目地址:http://oprofile.sourceforge.net/about/

6.1 初始化 oprofile(Initializing oprofile)

oprofile 首次使用时必须初始化。先找到与你正在运行的内核对应的 vmlinux 镜像:

ls /boot
sudo opcontrol --init
sudo opcontrol --setup --vmlinux={path-to-image} --separate=library --callgraph=6
参数 说明
--vmlinux={path-to-image} 与当前运行内核对应的 vmlinux 镜像路径(先用 ls /boot 找)
--separate=library 按库分离采样
--callgraph=6 开启 call graph,深度 6

6.2 启动 oprofile

opcontrol --start

6.3 停止 oprofile

opcontrol --stop

6.4 获取 oprofile 结果(Retrieving oprofile Results)

取 top cmon 结果:

opreport -gal ./cmon | less

取 top cmon 结果,带 call graphs:

opreport -cal ./cmon | less
选项 含义
-g 按 symbol 粒度(含调试信息)显示
-a 累加(accumulate)
-c 显示 call graph
-l 按 symbol 显示

⚠️ 重要(官方原文):查看完结果后,再次运行 oprofile 之前要先 reset。reset 动作会清掉 session 目录里的数据。

6.5 重置 oprofile

sudo opcontrol --reset

⚠️ 重要(官方原文):分析完数据后要 reset oprofile。这能确保之前的测试结果不会混进当前测试的结果里。

引自:CPU Profiling


七、内存剖析(memory-profiling.rst)

7.0 前提与安装

Ceph Monitor、OSD 和 MDS 都能报告 TCMalloc heap profiles。 想生成这些报告,需要安装 google-perftools。

你的 OS 发行版可能用不同的名字打包(例如 gperftools),也可能用不同的包管理器。

sudo apt-get install google-perftools

输出位置:profiler 把输出 dump 到你的 log file 目录(/var/log/ceph)。详见 Logging and Debugging。

7.1 用 Google performance tools 查看 profiler 日志

google-pprof --text {path-to-daemon}  {log-path/filename}

完整示例(官方原文):

$ ceph tell osd.0 heap start_profiler
$ ceph tell osd.0 heap dump
osd.0 tcmalloc heap stats:------------------------------------------------
MALLOC:        2632288 (    2.5 MiB) Bytes in use by application
MALLOC: +       499712 (    0.5 MiB) Bytes in page heap freelist
MALLOC: +       543800 (    0.5 MiB) Bytes in central cache freelist
MALLOC: +       327680 (    0.3 MiB) Bytes in transfer cache freelist
MALLOC: +      1239400 (    1.2 MiB) Bytes in thread cache freelists
MALLOC: +      1142936 (    1.1 MiB) Bytes in malloc metadata
MALLOC:   ------------
MALLOC: =      6385816 (    6.1 MiB) Actual memory used (physical + swap)
MALLOC: +            0 (    0.0 MiB) Bytes released to OS (aka unmapped)
MALLOC:   ------------
MALLOC: =      6385816 (    6.1 MiB) Virtual address space used
MALLOC:
MALLOC:            231              Spans in use
MALLOC:             56              Thread heaps in use
MALLOC:           8192              Tcmalloc page size
------------------------------------------------
Call ReleaseFreeMemory() to release freelist memory to the OS (via madvise()).
Bytes released to the OS take up virtual address space but no physical memory.
$ google-pprof --text \
               /usr/bin/ceph-osd  \
               /var/log/ceph/ceph-osd.0.profile.0001.heap
 Total: 3.7 MB
 1.9  51.1%  51.1%      1.9  51.1% ceph::log::Log::create_entry
 1.8  47.3%  98.4%      1.8  47.3% std::string::_Rep::_S_create
 0.0   0.4%  98.9%      0.0   0.6% SimpleMessenger::add_accept_pipe
 0.0   0.4%  99.2%      0.0   0.6% decode_message
 ...

heap stats 输出字段解读

字段 含义
Bytes in use by application 应用正在使用的字节数
Bytes in page heap freelist page heap freelist 中的字节数
Bytes in central cache freelist central cache freelist 中的字节数
Bytes in transfer cache freelist transfer cache freelist 中的字节数
Bytes in thread cache freelists thread cache freelists 中的字节数
Bytes in malloc metadata malloc 元数据占用的字节数
Actual memory used (physical + swap) 实际使用的内存(物理 + swap)
Bytes released to OS (aka unmapped) 已通过 madvise() 释放给 OS 的字节数(占虚拟地址空间但不占物理内存)
Virtual address space used 使用的虚拟地址空间
Spans in use 在用 span 数
Thread heaps in use 在用 thread heap 数
Tcmalloc page size Tcmalloc 页大小(上例为 8192)

7.2 比较两个时间点的 heap dump(看"什么在涨")

在同一个守护进程上再做一次 heap dump,会生成另一个文件。 拿新文件与此前某次 dump 生成的文件做对比,可以看出这段时间里什么东西长大了——这是定位内存增长的最实用手法。

$ google-pprof --text --base out/osd.0.profile.0001.heap \
      ceph-osd out/osd.0.profile.0003.heap
 Total: 0.2 MB
 0.1  50.3%  50.3%      0.1  50.3% ceph::log::Log::create_entry
 0.1  46.6%  96.8%      0.1  46.6% std::string::_Rep::_S_create
 0.0   0.9%  97.7%      0.0  26.1% ReplicatedPG::do_op
 0.0   0.8%  98.5%      0.0   0.8% __gnu_cxx::new_allocator::allocate

详见 Google Heap Profiler:http://goog-perftools.sourceforge.net/doc/heap_profiler.html

7.3 四个 heap profiler 操作

装好 heap profiler 后,启动集群并开始使用 heap profiler。你可以在运行时启用或禁用 heap profiler,也可以让它持续运行。

跑下面的示例命令时:{daemon-type} 替换为 mon、osd 或 mds;{daemon-id} 替换为 OSD 编号、MON ID 或 MDS ID。

7.3.1 启动 Profiler(Starting the Profiler)

ceph tell {daemon-type}.{daemon-id} heap start_profiler

例如:

ceph tell osd.1 heap start_profiler

开机即启动:如果环境里有 CEPH_HEAP_PROFILER_INIT=true 变量,那么守护进程启动时 profiler 就会被启动。

7.3.2 打印统计(Printing Stats)

ceph  tell {daemon-type}.{daemon-id} heap stats

例如:

ceph tell osd.0 heap stats

注:用这条命令报 stats 不需要 profiler 正在运行,并且不会把 heap 分配信息 dump 到文件。

7.3.3 Dump Heap Information

ceph tell {daemon-type}.{daemon-id} heap dump

例如:

ceph tell mds.a heap dump

注:dump heap 信息只在 profiler 运行时才有效。

7.3.4 释放内存(Releasing Memory)

释放 tcmalloc 已分配但未被 Ceph 守护进程本身使用的内存:

ceph tell {daemon-type}{daemon-id} heap release

例如:

ceph tell osd.2 heap release

💡 补充:注意这条命令在官方原文里的形态是 {daemon-type}{daemon-id}(中间没有点号),与前几条(. 分隔)写法不一致;本册照录原文写法。实际执行时按所用版本支持的形式为准(本册源文未对这一差异给出解释)。

7.3.5 停止 Profiler

ceph tell {daemon-type}.{daemon-id} heap stop_profiler

例如:

ceph tell osd.0 heap stop_profiler

heap 命令速查

操作 命令 是否要求 profiler 在跑
启动 ceph tell osd.1 heap start_profiler ——
打印统计 ceph tell osd.0 heap stats 否(且不落文件)
dump ceph tell mds.a heap dump 是
释放内存 ceph tell osd.2 heap release 文档未明确
停止 ceph tell osd.0 heap stop_profiler ——
开机自启 环境变量 CEPH_HEAP_PROFILER_INIT=true ——

7.4 另一种内存剖析法:Valgrind + Massif

适用场景:Massif heap profiler 工具可以与 Valgrind 一起使用,测量使用了多少 heap 内存。这个方法很适合排查 RadosGW。

详见 Massif 文档:https://valgrind.org/docs/manual/ms-manual.html

步骤:

  1. 从你的发行版包管理器安装 Valgrind,然后启动你要排查的 Ceph 守护进程:
sudo -u ceph valgrind --max-threads=1024 --tool=massif /usr/bin/radosgw -f --cluster ceph --name NAME --setuser ceph --setgroup ceph
  1. 该命令运行结束后,会在当前工作目录生成一个名为 massif.out.<pid> 的文件。要跑上面这条命令,执行它的用户必须对当前目录有写权限。

  2. 跑 ms_print 从收集到的数据里拿到图和统计:

ms_print massif.out.12345

该命令的输出在提交 bug report 时很有帮助。

引自:Memory Profiling


八、社区求助渠道(community.rst)

8.1 邮件列表

邮件列表 适用 订阅 退订
ceph-users 运维(operational)问题——官方推荐 ceph-users-join@ceph.io ceph-users-leave@ceph.io
ceph-devel 你的问题疑似 bug;与开发版发布包相关;与开发测试包相关;与你自己的构建相关 dev-join@ceph.io dev-leave@ceph.io

官方原文:Ceph 社区是极好的信息和帮助来源。对于 Ceph 的运维问题,我们推荐订阅 ceph-users 邮件列表。

该发到哪个列表?

你的情况 建议
一般运维问题 ceph-users
疑似 bug ceph-devel
开发版发布包相关 ceph-devel
开发测试包相关 ceph-devel
你自己构建的 Ceph ceph-devel

💡 补充:troubleshooting-mon.rst 里给出的列表地址写作 dev@ceph.io 和 ceph-users@lists.ceph.com,与 community.rst 中的 dev-join@ceph.io / ceph-users-join@ceph.io 写法不同——前者是发帖/联系地址,后者是订阅/退订地址。本册不判断二者是否等同,仅照录原文。

8.2 IRC / Slack / 其他

(来自 troubleshooting-mon.rst 的 "Reaching out for help")

渠道 地址
IRC #ceph 和 #ceph-devel,在 OFTC(server irc.oftc.net)
邮件 dev@ceph.io、ceph-users@lists.ceph.com
Slack 上游 Ceph Slack workspace:https://ceph-storage.slack.com/
综合联系方式 https://ceph.io/en/community/connect/ (页面标注为 2023 年 12 月的当前信息)

8.3 ceph report:求助时最该附带的东西

官方 tip:如果你提供关于问题的详细信息,社区成员就能帮到你。附上 ceph report 命令的输出,帮助别人理解你的问题。

ceph report

8.4 报告 bug 的方式与应提供的信息

开 issue

应提供的信息(按来源汇总)

来源 应提供的信息
community.rst ceph report 的输出
troubleshooting-mon.rst(准备日志) ① 定位 MON 日志(ceph-conf --name mon.FOO --show-config-value log_file);② 先把 debug 提到 debug_mon = 10、debug_ms = 1 再复现;③ 记下复现时的日期时间,据此截取日志片段(不要甩几十万行无说明的日志);④ 通过邮件列表 / IRC / Slack 联系,或在 tracker 开新 issue
troubleshooting-osd.rst(段错误时) 正在运行的具体 Ceph 版本、ceph.conf(敏感信息用 XXX 打码)、monitor status 输出、日志文件摘录;先去 bug tracker 与 dev/ceph-users 归档搜索是否有人报过
troubleshooting-osd.rst(软件错误时) 先搜 bug tracker / dev 邮件列表归档(https://lists.ceph.io/hyperkitty/list/dev@ceph.io/)/ ceph-users 归档(https://lists.ceph.io/hyperkitty/list/ceph-users@ceph.io/);无既有结论则向 ceph-devel 报告
memory-profiling.rst ms_print massif.out.<pid> 的输出——提交 bug report 时很有帮助
troubleshooting-pg.rst 官方给出的 PG 手工修复 walkthrough:https://ceph.io/geen-categorie/ceph-manually-repair-object/

求助信息检查清单(把上面整理成可执行清单)

[ ] 1. ceph report 的完整输出
[ ] 2. ceph health detail 的输出
[ ] 3. 正在运行的 Ceph 具体版本
[ ] 4. ceph.conf(把 secrets 用 XXX 打码)
[ ] 5. monitor status 输出(ceph tell mon.ID mon_status)
[ ] 6. 相关日志片段(先把 debug_mon=10 / debug_ms=1 打开再复现;
[ ]    记下复现时刻,据此截取;不要一次发几十万行无说明日志)
[ ] 7. 复现步骤 + 复现时间
[ ] 8. 如涉及内存:ms_print massif.out.<pid> 的输出
[ ] 9. 已做过哪些排查(避免社区重复建议)

引自:The Ceph Community、Troubleshooting Monitors


九、排障速查表

9.1 命令速查(按场景)

场景 命令
第一动作 ceph health detail
集群状态 ceph status / ceph -s;指定 MON:ceph status -m mymon1
集群整体容量 ceph df(关注最满的 OSD)
单 OSD 容量 ceph osd df
谁 down 了 ceph osd tree down
OSD 拓扑 ceph osd tree
时钟偏移 ceph time-sync-status(Luminous+)
—— MON ——
MON 状态 ceph tell mon.ID mon_status
绕过 MON 直连 asok ceph --admin-daemon <full_path_to_asok_file> <command>
查 asok 路径 ceph-conf --name mon.ID --show-config-value admin_socket
查 MON 日志路径 ceph-conf --name mon.FOO --show-config-value log_file
有 quorum 调 debug ceph tell mon.FOO config set debug_mon 10/10 / ceph tell mon.* config set debug_mon 10/10
无 quorum 调 debug ceph daemon mon.FOO config set debug_mon 10/10
还原 debug 同上命令,把 10/10 换成 1/10
查当前配置 ceph daemon mon.FOO config show / config get 'OPTION_NAME'
取 monmap(有 quorum) ceph mon getmap -o /tmp/monmap
取 monmap(无 quorum) ceph-mon -i ID-FOO --extract-monmap /tmp/monmap
注入 monmap(危险) ceph-mon -i ID --inject-monmap /tmp/monmap
停 MON service ceph -a stop mon.{mon-id}
—— OSD ——
列日志 ls /var/log/ceph
列 asok ls /var/run/ceph
asok 帮助 ceph daemon {daemon-name} help / ceph daemon {socket-file} help
运行时配置 ceph daemon osd.0 config show | less
运行时注入 ceph tell osd.0 config set debug_osd 0/5 / sudo ceph daemon osd.0 config set debug_osd 0/5
文件系统空间 df -h
I/O iostat -x
内核消息 dmesg | grep scsi;dmesg -T
网络 netstat -a | grep ceph;netstat -l | grep ceph;sudo netstat -p | grep ceph;netstat -s
硬盘健康 smartctl
提高线程上限 sysctl -w kernel.pid_max=4194303
停 OSD 不 rebalance ceph osd add-noout osd.0 / ceph osd set-group noout <bucket>
恢复 ceph osd rm-noout osd.0 / ceph osd unset-group noout <bucket>
治 flapping ceph osd set noup + ceph osd set nodown;恢复 unset noup / unset nodown
看 flag ceph osd dump | grep flags
调满阈值 ceph osd set-nearfull-ratio / set-full-ratio / set-backfillfull-ratio
标记 OSD lost(危险) ceph osd lost 1
慢请求诊断 ceph daemon osd.<id> dump_historic_ops;ceph daemon osd.<id> dump_ops_in_flight
mClock HDD 调优(需重启) ceph config set osd osd_op_num_shards_hdd 1;ceph config set osd osd_op_num_threads_per_shard_hdd 5
起停 systemctl stop ceph\*.service ceph\*.target;sudo systemctl start ceph.target
—— PG ——
列 stuck ceph pg dump_stuck stale / inactive / unclean
查 PG 卡因 ceph pg 0.5 query
列 unfound ceph pg 2.4 list_unfound [starting offset, in json]
放弃 unfound(危险) ceph pg 2.5 mark_unfound_lost revert|delete
修 inconsistent ceph pg repair {placement-group-ID}
列 inconsistent PG rados list-inconsistent-pg rbd
列 inconsistent obj rados list-inconsistent-obj 0.6 --format=json-pretty
强制建空 PG ceph osd force-create-pg <pgid>
列池编号 ceph osd listpools / ceph osd dump | grep pool
—— CRUSH ——
列 rule ceph osd crush rule ls
dump rule ceph osd crush rule dump erasurepool
导出 map ceph osd getcrushmap > crush.map
反/编译 crushtool --decompile crush.map > crush.txt;crushtool --compile crush.txt -o better-crush.map
离线测映射 crushtool -i crush.map --test --show-bad-mappings --rule 1 --num-rep 9 --min-x 1 --max-x $((1024 * 1024))
测尝试次数 同上再加 --show-choose-tries
EC profile ceph osd erasure-code-profile set myprofile k=5 m=3;... crush-failure-domain=osd
—— 剖析 ——
heap 启/停 ceph tell osd.N heap start_profiler / stop_profiler
heap stats / dump ceph tell osd.N heap stats / heap dump
heap 释放 ceph tell osd.N heap release
看 heap 文件 google-pprof --text {path-to-daemon} {log-path/filename}
对比两次 dump google-pprof --text --base out/osd.0.profile.0001.heap ceph-osd out/osd.0.profile.0003.heap
Massif sudo -u ceph valgrind --max-threads=1024 --tool=massif /usr/bin/radosgw -f --cluster ceph --name NAME --setuser ceph --setgroup ceph;ms_print massif.out.12345
oprofile sudo opcontrol --init;--setup --vmlinux=... --separate=library --callgraph=6;--start;--stop;--reset;opreport -gal ./cmon;opreport -cal ./cmon
—— 求助 ——
报告 ceph report
开 issue http://tracker.ceph.com/projects/ceph/issues/new

9.2 关键参数速查(默认值务必与官方一致)

参数 默认值 含义
mon_osd_full_ratio 0.95 OSD 满阈值,超过则阻止客户端写入
mon_osd_backfillfull_ratio 0.90 超过则不启动 backfill
mon_osd_nearfull_ratio 0.85 触发 OSD_NEARFULL
mon-clock-drift-allowed 0.05 秒(50 毫秒) 最大可容忍时钟偏移
osd_op_complaint_time 30 秒 slow request 告警阈值
osd_scrub_auto_repair false EC/BlueStore 池自动修复开关
osd_scrub_auto_repair_num_errors 5 自动修复允许的最大错误数
osd_op_num_shards_hdd 5(问题配置)→ 改为 1 mClock HDD OSD shard 数
osd_op_num_threads_per_shard_hdd 1(问题配置)→ 改为 5 mClock HDD 每 shard 线程数
osd_crush_chooseleaf_type 1(host/node);单节点改 0(osd) CRUSH chooseleaf 类型
osd_pool_default_size 文档未明确(>2 可致 PG 不 clean) 池副本数
osd_pool_default_min_size 文档未明确(两副本场景建议设 2) 允许写入的最小副本数
kernel.pid_max 通常 32,000;可提到 4194303 最大线程数
set_choose_tries 大于默认值(示例中设 100) CRUSH 选择尝试次数
rotate / 频率 / size 7 / weekly / 示例 500M logrotate 设置
debug_mon / debug_ms(求助建议值) 10 / 1 MON 排障建议 debug 级别
CEPH_HEAP_PROFILER_INIT true 时开机自启 heap profiler 环境变量
每 OSD 内存建议 最低 4GB,建议 6GB→8GB RAM 建议
MON 端口 6789(互联还含 tcp/3300) 端口
OSD 端口 6800 - 7568 端口
ITEM_NONE 2147483647 CRUSH 找不到 OSD 的占位值

9.3 场景 → 第一命令 对照表

你看到的现象 第一命令 跳转
集群报 HEALTH_ERR/WARN 但不知道是谁 ceph health detail 1.2
mon.X is down (out of quorum) ceph tell mon.X mon_status 3.4
clock skew ... > max 0.05s ceph time-sync-status 3.6
MON 日志出现 Corruption: error in middle of record 换 MON / ceph-objectstore-tool 恢复 3.8
1/3 in osds are down ceph osd tree down + ls /var/log/ceph 4.4
1 full osd(s) / nearfull ceph osd df + ceph df 4.5
OSD 反复 up/down ceph osd set noup + ceph osd set nodown 4.7
N slow requests ... blocked for > 30 secs ceph daemon osd.<id> dump_ops_in_flight 4.6.12
mClock HDD 集群慢 + queued_for_pg 居多 改 shard 配置并错峰重启 OSD 4.6.14
PG 一直是 active+degraded 不 clean 查 osd_pool_default_size / osd_crush_chooseleaf_type 5.1
pg N.N is down+peering ceph pg N.N query 5.3
N unfound ceph pg N.N list_unfound 5.4
N pgs stale ceph health detail(看 last acting) 5.5
pg N.N is active+clean+inconsistent rados list-inconsistent-pg <pool> → rados list-inconsistent-obj N.N 5.8
EC PG 映射里出现 2147483647 crushtool -i crush.map --test --show-bad-mappings ... 5.9
想查内存涨在哪 heap start_profiler → heap dump → google-pprof --text --base ... 7.2
要向社区求助 ceph report + debug_mon=10/debug_ms=1 下的日志片段 8.3

文档未明确项

本册严格依据 doc/rados/troubleshooting/ 下 8 个 rst 源文撰写。以下内容源文未提供,在此集中列出,避免读者误以为遗漏:

# 未明确内容 所在位置 说明
1 ceph -w 的用法与输出 第一章 1.3 该命令未出现在本册 8 个源文中;官方未描述其行为
2 log_file、log_max_new、log_max_recent、log_to_file、log_to_stderr、err_to_stderr、log_to_syslog、err_to_syslog、log_flush_on_exit、clog_to_monitors、clog_to_syslog 的默认值与描述 第二章 2.8 log-and-debug.rst 仅以 confval 列出名字,未在本页展开
3 mon_cluster_log_*、mon_log_max、mon_health_to_clog* 的默认值与描述 第二章 2.8 同上
4 osd_debug_drop_ping_probability、osd_debug_drop_ping_duration 的默认值 第二章 2.7 / 2.8 同上
5 filestore_debug_omap_check、mds_debug_*、rgw_* 各日志项的默认值 第二章 2.8 同上
6 slow request 相关参数**(除 osd_op_complaint_time 及 mClock 两项外)**的完整清单 第二章 2.7 源文未给出 slow request 参数族的系统列表
7 leveldb 与 rocksdb 各自的损坏判定与修复差异 第三章 3.8.1 官方只给了两条通用 Corruption: 错误文本,未区分后端
8 mon_osd_down_out_interval 的具体默认值 第四章 4.7 源文只提到 noout 会无视其"当前值",未给默认值
9 mon_osd_down_out_subtree_limit、mon_osd_reporter_subtree_level、mon_osd_min_down_reporters 的最优设置 第四章 4.7 官方明确说"最优设置的推导取决于集群规模、拓扑和 Ceph 版本……超出了本文档的范围"
10 osd_pool_default_size / osd_pool_default_min_size 的默认数值 第五章 5.1 源文只说"大于 2 会导致 PG 不 clean"、"建议设 2",未给默认值
11 PG 处于 incomplete 状态的成因与排查方法 第五章 本册 8 个源文中完全没有 incomplete 这一 PG 状态;官方在 troubleshooting-pg.rst 只覆盖了 active/degraded/remapped/down/peering/stale/unfound/inconsistent
12 snaptrim 相关排障(snaptrim 卡住、snaptrim error 等) 第五章 本册 8 个源文中完全没有 snaptrim 内容
13 set_choose_tries 的默认值 第五章 5.9.3 源文只说"设置为大于默认值的值",未给具体默认数
14 osd_op_num_shards_hdd / osd_op_num_threads_per_shard_hdd 是否为全局默认值 第四章 4.6.14 源文只说这段排障适用于"配置为 5 和 1"的场景,未说明这是默认还是被改过的值
15 ceph tell {daemon-type}{daemon-id} heap release 中缺少点号的写法是否笔误 第七章 7.3.4 源文确实写成 {daemon-type}{daemon-id},本册照录,未作判断
16 nf_conntrack_max / nf_conntrack_buckets 的推荐具体数值 第四章 4.3 源文只给关系式 buckets × 8 = max 和一个 echo 131072 > ...hashsize 示例,未给推荐值
17 ceph report 的完整输出结构与字段含义 第八章 8.3 源文仅建议"附上 ceph report 的输出",未展开
18 MON store 恢复脚本中 $hosts 变量如何赋值 第三章 3.8.3 源文脚本直接使用 $hosts,未说明其定义方式