CephFS 的运维里,OSD 的增删大概是最高频、也最容易被“看轻”的操作。很多刚接触 Ceph 的同学觉得,加个盘不就是ceph-volume lvm create一下,删个盘不就是ceph osd rm一条命令的事?但实际上,OSD 增减背后牵扯着数据分布、集群复均衡、PG 迁移、性能抖动,甚至整个集群的稳定性。我在实际维护 CephFS 集群的过程中踩过不少坑,也总结了一套相对稳妥的操作流程,这篇就把 OSD 增删的底层逻辑、完整操作路径和实战注意事项一次性讲清楚。
1. OSD 在 CephFS 中的角色与“增删”背后的本质
1.1 OSD 是什么,CephFS 为什么依赖它
OSD(Object Storage Daemon)是 Ceph 集群中最核心的存储进程,每一个 OSD 通常对应一块物理磁盘或一个逻辑卷,负责承载数据对象的存储、复制、恢复和再均衡。CephFS 是构建在 Ceph 之上的分布式文件系统,用户看到的目录、文件最终会被切割成对象,通过 MDS(MetaData Server)管理元数据,再按照 CRUSH 算法把对象分布到集群的各个 OSD 上。
换句话说,CephFS 的高可用、高扩展,依赖的是底层 OSD 的数量和健康状态。OSD 太少,集群容量和性能都受限;OSD 故障,数据可能出现丢失或降级;OSD 分布不均,某些节点的磁盘会先被写满,进而拖垮整个存储池。
1.2 “增删”不只是磁盘的插拔,而是数据分布的重构
从操作上看,加一个 OSD 是让集群多一个可用的存储单元,删一个 OSD 是让集群去掉一个存储单元。但从数据层面看,每一次增删都会触发 CRUSH 算法的重新计算,使得部分 PG(Placement Group)从旧 OSD 迁移到新 OSD,或者从被删除的 OSD 迁移到集群其他成员上。
这个“数据重构”过程,才是 OSD 增删操作真正的核心。
很多刚入门的同学容易忽略一点:CRUSH 映射(crush map)决定了数据分布,而 OSD 的增删会改变 crush map 中的设备列表和设备权重。因此,集群会自动开始数据迁移。这种迁移会占用网络带宽、磁盘 IO 和 CPU 资源,如果集群处于高负载状态,迁移会造成明显的性能波动。
所以,评价一个运维同学是否真的懂 Ceph,不是看他会不会敲命令,而是看他能不能把“数据迁移”这件事控制得平稳、可控。
1.3 需要增删 OSD 的典型场景
在实际生产环境中,OSD 增删的需求主要来自以下几个方面:
- 容量扩容:集群空间不足,需要增加新磁盘或新节点。
- 性能扩容:现有 OSD 数量不足以支撑更高的 IOPS 或带宽需求,需要横向扩展。
- 硬件替换:磁盘老化、故障预警、SSD 替换 HDD,需要先删旧 OSD 再增加新 OSD。
- 节点下线:某个物理机器需要退租或维修,需要将这台机器上的 OSD 全部下线。
- 存储池分布调整:某些业务数据希望分布到更高性能的存储池中,需要调整 OSD 布局。
每一种场景下,“增”和“删”的侧重点不同。扩容时关注数据能否均匀分布,缩容时关注数据能否安全迁走,替换时关注新旧交替期间集群能否保持可用。
2. 添加 OSD 的完整实操与底层逻辑
2.1 添加前的准备工作
先别急着敲命令,准备工作做不好,后面会非常痛苦。
首先是磁盘层面的检查。需要确认新磁盘能被系统正确识别,没有残留的分区表和文件系统。我习惯在接入新盘后先用lsblk查看磁盘列表,再用blkid检查分区信息。如果是旧盘或者从其他环境拆下来的盘,需要用wipefs -a清掉残留的签名,否则 ceph-volume 大概率会报错。
然后是文件系统和目录规划。Ceph 的 OSD 数据目录通常放在独立的数据盘上。对于每个 OSD 数据盘,block 和 block.db 可以由 ceph-volume 自动处理。如果使用了独立的 SSD 作为 WAL/DB 盘,需要提前做好分区。
以下是我常用的一个磁盘检查参考流程:
# 查看新增磁盘 lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT # 检查是否残留签名 blkid /dev/sdb # 如果有残留,清掉签名 wipefs -a /dev/sdb # 如果是全新盘,建议先做一次坏道检测(可选,看时间是否允许) badblocks -sv /dev/sdb注意:
wipefs -a会清除磁盘上的所有分区表和签名,执行前必须确认盘符没有写错。我见过有运维同学把系统盘当成数据盘清掉的,这个失误一旦发生,基本无法挽回。
2.2 使用 ceph-volume 创建 OSD
Ceph 从 Luminous 版本之后,推荐使用ceph-volume来管理 OSD 的创建。它支持 LVM 和 raw 模式,其中 LVM 模式最常用。
对于一块裸数据盘,使用 ceph-volume 自动创建 OSD 的典型流程如下:
# 查看 ceph-volume 支持的子命令 ceph-volume lvm --help # 查看可用的磁盘 ceph-volume lvm list # 创建 OSD(自动创建一个新的逻辑卷并初始化为 OSD) ceph-volume lvm create --data /dev/sdb # 如果使用独立的 SSD 作为 WAL/DB,可以这样指定 ceph-volume lvm create --data /dev/sdb --block.db /dev/sdc1ceph-volume lvm create做的事情其实很多,会依次完成:
- 在数据盘上创建新的 LVM 逻辑卷。
- 生成 OSD 的 fsid。
- 写入 OSD 的配置信息。
- 挂载数据目录到
/var/lib/ceph/osd/ceph-<osd-id>。 - 启动 OSD 进程。
一个容易被忽略的细节是:ceph-volume lvm create执行完后,OSD 会自动加入集群并参与数据分布。此时不需要手动设置 crush weight,Ceph 会根据磁盘容量自动计算。
2.3 使用 cephadm 的 Orchestrator 方式(新版本推荐)
如果你使用的是 Ceph 较新版本,比如 Pacific(16)或 Quincy(17)以上,并且通过 cephadm 部署集群,可以直接用ceph orch来管理 OSD。
首先需要标记磁盘为可用:
# 查看集群可用的磁盘 ceph orch device ls # 将某块盘设置为可用状态 ceph orch device zap <hostname> /dev/sdb --force然后创建 OSD:
ceph orch daemon add osd <hostname>:/dev/sdb或者直接采用驱动组(drive group)的方式,把节点上的可用盘统一加到集群里:
ceph orch apply osd --all-available这种方式非常适合大规模集群的自动化部署,可以减少重复劳动。不过,我在生产环境里还是倾向于手动指定盘,避免因为设备名漂移导致给错误的磁盘创建 OSD。
2.4 验证添加结果与数据分布效果
新增 OSD 完成后,需要确认集群状态是否健康,数据是否开始迁移。
最直接的验证方式是查看集群整体状态:
ceph -s重点关注几个指标:
HEALTH_OK:集群健康,没有报错。PGs的状态:新增 OSD 后,部分 PG 会进入active+remapped状态,表示正在迁移数据。osdmap的变化:确认新 OSD 已经被加入 map。
然后查看 OSD 级别的分布情况:
ceph osd tree这个命令会输出每个 OSD 所在的主机、状态、权重等信息。可以看到新 OSD 的状态是否为up和in。
进一步查看权重和容量使用情况:
ceph osd dfceph osd df输出的信息包含每个 OSD 的总容量、已用容量、数据占比和权重。通过对比新 OSD 与旧 OSD 的数据占比,可以判断数据是否在向新 OSD 均匀流动。
2.5 新 OSD 的权重调整问题
默认情况下,Ceph 会根据磁盘容量自动设置 OSD 的 crush weight。比如一块 4T 的盘权重约 4.0,2T 的盘权重约 2.0。
但有时候,我们希望手动调整权重。典型的场景是:新加的盘容量大,但希望它承担更多数据;或者混合了不同容量的盘,希望某个盘别先写满。
调整权重使用下面的命令:
ceph osd crush reweight osd.<id> <weight>这里<weight>是浮点数,通常与磁盘容量单位对应。比如 4T 盘设为 4.0,8T 盘设为 8.0。
注意:
ceph osd crush reweight修改的是 CRUSH 权重,会影响数据分布的目标比例。修改后集群会立即开始数据迁移。不要在业务高峰期做这种操作,否则容易引发性能抖动。
3. 删除 OSD 的优雅流程与数据迁移控制
3.1 删除 OSD 前的必要评估
删除 OSD 比添加 OSD 风险更高。因为 OSD 一旦被移除,它上面承载的数据必须全部迁移到其他 OSD 上。如果集群剩余容量不足,迁移会失败;如果剩余 OSD 数量太少,可能无法满足数据冗余策略,集群会进入降级状态。
所以在删除之前,我建议先做一组检查:
# 查看集群整体状态 ceph -s # 查看目标 OSD 的容量使用情况 ceph osd df tree # 查看剩余 OSD 的可用空间 ceph osd df # 查看目标 OSD 服务的 PG 数量 ceph pg ls-by-osd | grep <osd_id> | wc -l重点确认两点:剩余空间是否充足,剩余 OSD 是否足够。比如一个三副本存储池,如果集群最后只剩两个 OSD,数据是无法满足三副本要求的。
3.2 标准删除流程:out、等待迁移、停机、移除
删除 OSD 的标准流程,每一步都有它的逻辑意义。下面完整走一遍。
第一步:将 OSD 标记为 out
ceph osd out osd.<id>这一步的逻辑是:告诉 CRUSH 算法,这个 OSD 不再承担新的数据分布,同时触发数据迁移。它上面的 PG 会逐步迁移到其他 OSD 上。
标记 out 之后,需要等待集群自动完成迁移。这个等待时间取决于数据量、网络带宽和 OSD 性能。小集群可能几十分钟,大集群可能要几天。
查看迁移进度:
ceph -s此时应该看到部分 PG 处于active+remapped状态。当所有 PG 都回到active+clean,说明目标 OSD 上的数据已经全部迁走。
第二步:确认迁移完成且集群健康
当ceph -s显示HEALTH_OK,并且目标 OSD 的 PG 数量降为 0,可以继续下一步。
确认 PG 已经迁移干净的方法:
ceph pg ls-by-osd <osd_id> | grep -v "^PG" | tail -n +2 | wc -l这个输出结果为 0,说明目标 OSD 上已经没有 PG。
第三步:停止 OSD 进程
systemctl stop ceph-osd@<id>如果使用容器方式:
ceph orch osd rm stop <id>停止进程很重要,防止在移除过程中 OSD 还在尝试读写数据。
第四步:从 CRUSH map 中移除
ceph osd crush remove osd.<id>如果 OSD 已经不在 CRUSH map 中,这一步可以跳过。
第五步:删除 OSD 认证密钥
ceph auth del osd.<id>如果不删除,集群的认证数据库中会残留陈旧条目,日积月累会显得很乱。
第六步:从 osdmap 中彻底移除
ceph osd rm <id>执行到这里,OSD 已经彻底从集群中移除。
注意:如果只是想临时下线一个 OSD,而不是彻底删除,可以在第三步之前直接
ceph osd out即可。重新上线时只需要ceph osd in <id>。
3.3 删除过程中的数据迁移监控
删除 OSD 过程中,数据迁移的监控非常重要。除了用ceph -s查看 PG 状态,我还会用以下命令追踪细节:
ceph pg dump | grep -E "remapped|peered|recovering"这能看到具体的 PG 状态变化。更直观的方式是使用ceph -w实时跟踪:
ceph -w输出中会滚动显示系统事件、PG 状态变化和恢复速率。通过观察 recovery 速率,可以评估迁移大概需要多长时间。
3.4 删除节点上的多个 OSD:逐台下线策略
如果是整机下线,需要将这台机器上的所有 OSD 逐个下线。策略上,建议不要同时标记多个 OSD 为 out,否则会加重其他节点的数据迁移压力,甚至导致集群过载。
我通常的做法是:一个一个来,一个 OSD 数据迁完,再标记下一个。如果机器必须尽快下线,可以在标记第二个 OSD 时,通过调整osd_max_backfills参数引入并发上限,控制迁移速度。
3.5 reweight 和 out 的区别
ceph osd reweight <id> <weight>和ceph osd out <id>虽然都能让 OSD 的数据减少,但逻辑不同:
ceph osd out:把 OSD 从 CRUSH 中剔除,数据全部迁走,PG 数降到 0。ceph osd crush reweight:通过降低 CRUSH 权重,让 OSD 分到的数据减少,但不会完全清空。
实际运维中,如果只是想临时平衡磁盘空间,降低权重比直接 out 更温柔,不会造成大量 PG 同时迁移。但如果目标是不再使用这块盘,out 是更干净的选择。
4. 常见问题与排查技巧实录
4.1 数据迁移卡住,PG 一直 remapped
这是增删 OSD 时最常遇到的问题。现象是ceph -s中大量 PG 处于active+remapped,迁移进度迟迟不推进。
排查思路:
先看迁移是否真的在进行:
ceph pg query <pg_id>观察recovery_state部分。如果recovering字段显示大量字节正在恢复,说明迁移在继续,只是慢。如果完全没有变化,说明卡住了。
常见原因:
- 网络带宽被占满,迁移数据无法传输。
- 磁盘 IO 到瓶颈,比如大量随机读。
- 集群正在执行深度 scrub 或快照操作,影响了 IO。
osd_max_backfills设置过低,迁移并发受限。
解决办法:
# 临时提高迁移并发数 ceph tell osd.* injectargs '--osd-max-backfills 4' # 调整恢复速率 ceph tell osd.* injectargs '--osd-recovery-max-active 5'需要说明的是,提高并发会加大集群负载。在业务低峰期做这个操作,效果最好。
4.2 PG 数量下降到 0,但 OSD 依然有数据占用的错觉
有时候ceph pg ls-by-osd <id>输出为空,但ceph osd df显示这个 OSD 仍然有数据占用。这通常是因为 PG 虽然迁走了,但 OSD 上还残留了上一轮 PG 迁移产生的临时文件或快照数据。
这种情况一般不影响正常操作,但如果磁盘需要回收给其他用途,可以手动清理。最稳妥的方式是在确认没有任何 PG 之后,格式化磁盘并重新挂载。
4.3 删除 OSD 后发现其他 OSD 空间失衡
删除大容量 OSD 后,剩余 OSD 可能因为 CRUSH 重分布导致部分 OSD 写入远高于其他 OSD。这是 CRUSH 算法的统计特性引起的“简单随机导致局部不均衡”。
可以通过ceph osd df查看每个 OSD 的使用率,如果发现个别 OSD 使用率特别高,可以用ceph osd reweight-by-utilization做一次自动再均衡:
ceph osd reweight-by-utilization 105这个命令会把使用率超过平均 105% 的 OSD 权重降下来,让数据更多流向低使用率的 OSD。
4.4 OSD 进程无法停止,systemd 卡住
在删除 OSD 时,systemctl stop ceph-osd@<id>有时会卡住,原因是 OSD 进程正在处理 IO,无法立即退出。
这时候可以先用ceph tell osd.<id> dump_ops_in_flight查看是否有 IO 在途,再确认无大流量后强制停止:
systemctl kill -s SIGTERM ceph-osd@<id>如果 SIGTERM 也无效,再考虑 SIGKILL。但 SIGKILL 会导致 OSD 状态异常,甚至引发 PG 恢复流程的复杂变化。不到万不得已,不建议直接 kill -9。
4.5 使用 ceph orch osd rm 删除时被提示有保护策略
部分新版本集群默认启用了 OSD 删除保护,需要先关闭保护策略:
ceph config set mgr mgr/cephadm/osd_delete_protection false或者设置成允许:
ceph config set mgr mgr/cephadm/osd_delete_protection 'true'这个保护策略主要是防止误操作,正式环境建议保持开启,只在明确要删除 OSD 时临时调整。
4.6 磁盘故障导致的 OSD down
OSD 因磁盘故障突然 down,处理方式和主动删除不同,核心是“先恢复,再替换”。
先把故障 OSD 标记为 out:
ceph osd out <id>等待数据迁移完成后,停止 OSD 进程,按上面的删除流程移除。然后更换新盘,重新走添加 OSD 的流程。如果磁盘完全损坏,OSD 进程可能已经无法启动,此时需要直接清理 OSD 的 map 信息和 auth 信息。
5. 经验总结与操作建议
5.1 增删 OSD 应遵循的四个“黄金原则”
第一个原则:增删之前先看集群容量和 PG 分布。心里有数,操作才不慌。
第二个原则:删除操作一定走“out → 等待 → 停止 → 移除”的完整流程,不要跳步。跳过等待数据迁移,会导致数据丢失风险。
第三个原则:业务低峰期进行。OSD 增删引发的数据迁移会消耗大量系统资源,高峰期操作容易造成业务延迟。
第四个原则:保留操作日志。记录每次增删的时间点、OSD 列表、集群状态,方便回溯问题。
5.2 我个人在实际操作中的体会
我最初做 OSD 删除时,也有过“相对顺利”和“差点翻车”的经历。顺利的时候,几百个 PG 平稳迁移,集群状态一直保持健康,业务量几乎没感知。差点翻车的时候,是在业务高峰期删了一个 OSD,结果整个集群的写入延迟飙升,部分服务直接超时。
那次之后,我给自己定了个规矩:紧急操作之前,先在测试集群模拟一遍,评估数据迁移量和耗时。生产环境宁可多等一晚上,也不要试图“快刀斩乱麻”。
另外,监控系统一定要覆盖到 OSD 层面的关键指标,包括磁盘利用率、IO 延迟、网络吞吐量、PG 状态变化。这样每次增减 OSD,就能通过曲线变化直观地判断集群的健康走势。
5.3 后续扩展:从手动到自动化的演进
如果集群规模大了,手动增删 OSD 的方式会变得非常累。可以结合 cephadm 的 drive group 功能,把磁盘声明能力做成配置模板,实现新节点上线后自动发现磁盘并创建 OSD。这样既能减少人工操作,又能降低误操作概率。
还有一点,Ceph 的 OSD 管理能力在不同版本之间差异不小。如果你用的是较老版本,建议先查阅对应版本的官方文档,再结合你所在集群的实际环境操作。毕竟每个集群有自己独特的磁盘布局、网络结构和业务特点,把通用的方法落地到具体环境,才是最稳妥的做法。