
本文深入分析了 Ceph 存储集群中 OSD 重启失败的典型问题,从日志出发定位到 systemd 服务超时这一核心原因,并详细梳理了 ceph-disk 激活 OSD 的完整流程,为运维人员解决类似问题提供清晰的思路。
问题描述
客户在重启物理机后发现部分 OSD 未能成功启动。但通过手动执行 ceph-disk 命令可以成功激活 OSD。从系统日志中,我们筛选出了关键的时间线信息:
May 22 06:05:19 cephosd06 systemd[1]: Starting Ceph disk activation: /dev/sdh1...
May 22 06:05:30 cephosd06 sh[3926]: main_trigger: main_activate: path = /dev/sdh1
...
May 22 06:07:20 cephosd06 systemd[1]: ceph-disk@dev-sdh1.service: Main process exited, code=exited, status=124/n/a
May 22 06:07:20 cephosd06 systemd[1]: Failed to start Ceph disk activation: /dev/sdh1.
日志清晰地显示,服务在启动约 120秒 后因超时而失败(状态码124)。了解 systemd 的运维人员知道,这是典型的执行超时退出。
原因分析
导致此问题的原因主要有以下几点,它们可能单独或共同作用:
-
服务依赖与并发问题:ceph-disk 在激活过程中会通过 --runtime 参数调用 ceph-osd@{osd_id}.service。--runtime 意味着此启动项不会持久化,重启机器后不会自动生效。因此,在 systemd 中只需启用 ceph-disk@.service。如果同时也启用了 ceph-osd@.service,则可能引发服务启动的并发冲突,加剧启动失败的概率。
-
systemd 超时时间过短:检查 ceph-disk@.service 文件,发现其 ExecStart 命令被包裹在 timeout 120 中。
ExecStart=/bin/sh -c 'timeout 120 flock /var/lock/ceph-disk-$(basename %f) /usr/sbin/ceph-disk --verbose --l
这个120秒的超时设置偏小,当服务器重启后需要同时激活大量 OSD 磁盘时,ceph-disk 进程很容易因排队或磁盘响应慢而在120秒内未能完成所有操作,导致被强制终止。上游社区也已意识到此问题并有过相关修改讨论。
-
上层编排工具的影响:例如,在使用 Juju Charm 部署 Ceph 时,其 ceph-osd Charm 可能存在相关 bug,会进一步干扰 OSD 的正常启动流程。
作为对比,ceph-osd@.service 的配置则侧重于进程的持续运行和故障恢复:
ExecStart=/usr/bin/ceph-osd -f --cluster ${CLUSTER} --id %i --setuser ceph --setgroup ceph
Restart=on-failure
StartLimitInterval=30min
StartLimitBurst=30
RestartSec=20s
ceph-disk 触发与 OSD 启动流程
理解 ceph-disk 如何被触发以及其内部流程,有助于从根本上排查问题。以下是其核心步骤的梳理:
-
创建 Journal 分区:首先,Ceph 会创建一个类型标识符(typecode)为 45b0969e-9b03-4f30-b4c6-b4b80ceff106 的专用 Journal 分区。
sgdisk --new=${num}:0:+128M --typecode=${num}:45b0969e-9b03-4f30-b4c6-b4b80ceff106 -- /dev/loop0
-
触发 udev 事件:使用 partprobe 更新分区表后,会向 udev 守护进程发送事件。
-
udev 规则响应:udev 根据规则文件(如 /usr/lib/udev/rules.d/95-ceph-osd.rules)匹配到刚创建的 Journal 分区类型,并执行触发命令。
RUN+="/usr/sbin/ceph-disk --log-stdout -v trigger /dev/$name"
-
激活 Journal:ceph-disk-udev 脚本会进一步调用 ceph-disk -v activate-journal 来激活该 Journal 分区。
-
建立符号链接:Journal 分区的 UUID 会被写入 OSD 数据目录下的 journal_uuid 文件,并创建一个指向 /dev/disk/by-partuuid/ 下该分区的软链接 journal。
/var/lib/ceph/osd/ceph-1/journal -> /dev/disk/by-partuuid/9195fa44-68ba-49f3-99f7-80d9bcb50430
ceph-disk prepare 与 activate 伪代码解析
以下通过伪代码形式,详细拆解 ceph-disk prepare 和 activate 的关键操作,这对理解其在120秒内需要完成的工作量至关重要。
1. 准备阶段 (Prepare)
此阶段负责擦除磁盘、创建分区并格式化。
# 1. 清除现有分区
sgdisk --zap-all --clear --mbrtogpt -- /dev/loop0
# 2. 创建 Journal 分区 (较小,如128MB)
sgdisk --new=2:0:+128M --typecode=2:45b0969e-9b03-4f30-b4c6-b4b80ceff106 -- /dev/loop0
# 3. 创建数据分区 (占用其余空间)
sgdisk --largest-new=1 --typecode=1:89c57f98-2fe5-4dc0-89c1-f3ad0ceff2be -- /dev/loop0
# 4. 格式化数据分区 (例如为 XFS)
mkfs -t xfs -f -i size=2048 -- /dev/loop0p1
# 5. 临时挂载并初始化 OSD 元数据
mkdir /var/lib/ceph/tmp/mnt.XXXXXX
mount /dev/loop0p1 /var/lib/ceph/tmp/mnt.XXXXXX
# 写入集群 fsid、OSD uuid、journal_uuid 等关键文件
echo $fsid > /var/lib/ceph/tmp/mnt.XXXXXX/ceph_fsid
echo $osd_uuid > /var/lib/ceph/tmp/mnt.XXXXXX/whoami
echo $journal_uuid > /var/lib/ceph/tmp/mnt.XXXXXX/journal_uuid
ln -s /dev/disk/by-partuuid/$journal_uuid /var/lib/ceph/tmp/mnt.XXXXXX/journal
# 6. 修改数据分区类型标识为“就绪”状态
sgdisk --typecode=1:4fbd7e29-9d25-41b8-afd0-062c0ceff05d -- /dev/loop0
# 触发 udev,使新分区类型生效
udevadm trigger --action=add --sysname-match loop0
2. 激活阶段 (Activate)
此阶段由 udev 触发或手动执行,负责挂载数据盘并启动 ceph-osd 守护进程。
# 1. 检查并挂载 OSD 数据分区
blkid -p -s TYPE -o value -- /dev/loop0p1 # 确认文件系统类型
mkdir /var/lib/ceph/tmp/mnt.YYYYYY
mount -t xfs -o noatime,inode64 -- /dev/loop0p1 /var/lib/ceph/tmp/mnt.YYYYYY
# 2. 验证挂载点内容后卸载
umount /var/lib/ceph/tmp/mnt.YYYYYY
# 3. 正式挂载到 OSD 数据目录
mount -o noatime,inode64 -- /dev/loop0p1 /var/lib/ceph/osd/ceph-$id
# 4. 通过 systemd 启动 OSD 守护进程
systemctl disable ceph-osd@$id # 禁用持久化启动(由 ceph-disk 管理)
systemctl enable --runtime ceph-osd@$id # 启用运行时启动
systemctl start ceph-osd@$id # 启动服务
整个 activate 过程涉及多次磁盘操作、挂载和与 systemd 的交互,在分布式存储节点磁盘较多或系统负载高时,很容易突破预设的120秒限制。
解决方案与后续建议
- 调整超时时间:临时解决方案是修改
ceph-disk@.service 文件,增大 timeout 值(例如改为300秒),并重载 systemd 配置。
- 优化服务配置:确保只启用
ceph-disk@.service,避免与 ceph-osd@.service 产生并发。同时,可以评估使用更新的 ceph-volume 工具替代 ceph-disk,其设计更现代,对 systemd 的集成和管理也更友好。
- 排查上游问题:如果部署依赖于如 Juju Charm 等编排工具,需确认其版本是否存在已知的 OSD 启动 bug 并更新。
对于运维复杂的 Ceph 集群,深入理解其底层组件如 ceph-disk 与 systemd 的交互机制,是快速定位和解决此类启动问题的关键。