资讯动态

Ceph RBD删除后空间未释放?trash清理与对象回收实战指南

发布时间:2026/10/21 9:18:06 来源:尧图企业网站定制
处理这种问题我的第一反应是先别急着扩容也别怀疑删除操作失败。ceph df显示的空间没变化十有八九是对象没被真正清掉或者删除流程还没走完。标题里提到的“删除rbd的数据”大概率是通过rbd rm或rbd trash系列命令完成的但“删除”这个动作本身有好几层含义每层没做彻底都会让空间继续被占着。这篇文章就围绕我实际排查中的完整思路来写从原理到命令再到排障细节尽量一次讲透。1. 现象确认空间没释放卡在了哪个环节先复现一下典型场景。你执行了类似这样的操作rbd rm --pool mypool myimage命令输出正常rbd ls mypool里也看不到这个镜像了。但执行ceph df一看USED那一列纹丝不动RAW USED 也没有什么变化。这时候很多人会以为删除失败或者有bug其实大概率是删除流程没有真正走完。在动手排查前建议先把下面三条命令跑一遍确认当前状态ceph df ceph osd df tree rbd trash ls --pool mypool --all重点看rbd trash ls --all的输出。--all会把所有处于延迟删除状态、以及已经被删除但还未被清理的RBD镜像都列出来。如果这里能看到myimage那问题就非常明确了删除操作只是把镜像挪进了trash并没有触发真正的对象清理。为什么会这样这是Ceph从Luminous版本开始引入的机制变化。早期版本执行rbd rm是真的直接删除所有对象但这种方式有风险一旦镜像正被客户端挂载使用或者有快照、克隆依赖删除就会报错甚至导致数据不一致。所以后来的设计改成两步走先标记删除把镜像移入trash后台异步执行清理这个设计本身是为了安全但也让很多刚上手Ceph的人困惑——明明“删了”空间却没回来。另外一个常见场景是误用了rados rm直接删对象。有些人会直接进pool里摸对象然后执行rados rm删除看起来像镜像数据块的对象。这种操作不会更新RBD的元数据trash里没有任何记录但对象确实少了最终会留下一堆孤儿对象反而更难清理。后面我会单独讲孤儿对象的处理。所以第一步的确认工作就是把“删除方式”和“当前trash状态”弄清楚。你可以简单记一张对照表操作方式空间立即释放是否进入trash后续需要处理rbd rm镜像无快照、无clone通常延迟释放是执行 trash purgerbd rm镜像有快照否是清理快照链后再purgerbd rm镜像有clone子镜像否是先处理依赖再purgerados rm 手动删对象部分释放否需要孤儿扫描清理rbd trash rm 手动清理是否无需额外操作这张表基本上覆盖了我日常遇到的所有“空间没释放”的场景。你可以对照自己的操作路径先确定属于哪一类再往下走。2. 核心机制trash、延迟删除和依赖链要理解为什么空间没释放不能只停留在命令层面。Ceph RBD的删除链路设计本质上是在“安全”和“即时回收”之间做取舍。我拆成几个关键机制来逐个说明。2.1 trash机制删除不是销毁rbd rm执行后镜像不会立刻被销毁而是被打上“已删除”标记移入pool的trash命名空间里。这个设计模仿了文件系统回收站的概念目的是防止误删。rbd trash ls能看到这些镜像它们的状态可能是removing、watched或者watcher。这里有一个关键参数rbd_trash_remove_delay。这个参数控制镜像进入trash后至少要等多少秒才能被真正清理。默认值在某些版本里是0但生产环境里很多团队会设置成1小时甚至24小时用来给误操作留出恢复窗口。如果你在ceph config dump里看到了类似配置ceph config get client.rbd rbd_trash_remove_delay输出值如果大于0那即使你手动执行rbd trash purge也需要等延迟时间过了之后才会真正清理。这个是很多排障过程中被忽略的点明明命令执行了空间却纹丝不动就是因为在等待期。2.2 延迟清理和watch状态第二个机制是watch状态。RBD块设备在被客户端挂载时客户端会对镜像维持一个watch通知机制。如果镜像正在被某个客户端使用OSD层面上存在对应watcher此时执行删除会进入“等待watcher断开”的状态。你会看到trash里的镜像状态变成watched。这意味着即使你执行了rbd trash purge如果没有先断开客户端的连接比如卸载文件系统、停止虚拟机清理动作也会一直等下去。我在生产环境里踩过这个坑有个云平台的虚拟机还在运行底层RBD已经被管理员手动删掉了结果trash清理持续了好几天磁盘空间一直在告警。2.3 快照链和clone依赖第三个机制是快照和克隆。RBD创建快照以后快照对象和当前镜像对象之间是有引用关系的。删除镜像时如果快照还在系统不会真正释放对象空间因为快照还引用着这些对象。更麻烦的是clone依赖。假设镜像A创建了快照snap_A然后从这个快照clone出镜像B。这时候B是A的childA的快照被B引用。删除A时系统必须保证B仍然能读取A的快照数据。结果就是A虽然被删除了但A的快照对象会被保留空间自然无法释放。我曾经维护过一个测试环境开发同事批量创建了一批克隆虚拟机后来虚拟机删除了但父镜像始终无法release空间原因就是子镜像的引用关系没有解除。最终需要手动检查并解除clone关系才算真正释放了空间。2.4 理解object与PG的关系最后要说一下底层存储模型。RBD镜像的每个数据块在Ceph中对应一个object这些object根据pool的PG数量分布到各个OSD上。删除镜像的本质是把这些object一个个删除掉。但OSD删除对象后对应的空间不会立刻返回“可用”。Ceph的OSD采取journaling和日志先写机制删除操作需要完成日志提交、PG更新、副本同步等步骤。在大规模集群里一次删除大量对象会产生很高的IO负载如果OSD的Backfill或Recovery正在进行这些删除操作会被延后。所以有时候你会看到trash已经清空了但空间还在缓慢变化这就是后台在慢慢处理对象删除。3. 实践操作从trash清理到对象级检查确认机制之后就可以动手解决了。下面这组操作顺序是我在多个集群上验证过的“标准排障流程”用它基本能处理掉90%以上的“空间未释放”问题。3.1 第一步清理trash先列出trash里的内容rbd trash ls --pool mypool --all如果发现有镜像先用rbd trash rm指定彻底删除某个镜像rbd trash rm --pool mypool myimage如果你确定当前trash里所有镜像都不需要了直接purge整个pool的trashrbd trash purge --pool mypool注意purge会删除该pool下trash里的所有镜像操作前一定再确认一遍列表。执行完后立刻再看一遍trash列表确认清空rbd trash ls --pool mypool --all此时如果ceph df的空间开始变化那就说明问题上文在第一步就解决了。3.2 第二步检查快照和clone如果trash已经清空了空间还是没释放很大概率存在快照或clone依赖。先查看pool下所有镜像rbd ls --pool mypool --long对每一个镜像检查它的快照列表和childrenrbd snap ls --pool mypool myimage rbd children --pool mypool myimage --snap snapnamerbd children会列出依赖这个快照的所有子镜像。如果存在子镜像你需要先处理子镜像或者解除它们对这个快照的依赖然后才能删除快照。确认快照可以删后执行rbd snap rm --pool mypool myimagesnapname3.3 第三步处理watcher如果trash里的镜像状态一直是watched先确认哪个客户端还在连接rbd status --pool mypool myimage输出里会显示watcher的ip和进程。这时候有两个选择正常卸载客户端推荐确认业务侧已经不再使用该设备从虚拟机/容器里卸载或断开连接watcher会自动消失。强制丢弃watcher危险只有当你非常确定客户端已挂死、不会再有IO时才建议执行rbd watch reset --pool mypool myimage这个命令会强制清除所有watcher让删除流程继续。但如果有客户端实际上还在写数据会造成数据损坏务必谨慎。3.4 第四步定位孤儿对象trash、快照、watcher都处理完了空间还是没释放那就要怀疑是不是有孤儿对象占着空间。这些对象可能是历史上用rados rm直接删对象造成的也可能是一次异常中断的删除操作留下的。查pool里的对象情况rados ls --pool mypool | head -n 20 rados du --pool mypoolrados du会给出每个对象的size信息有助于判断哪些对象占了大量空间。找到疑似孤儿对象后先确认它不属于任何已知RBD镜像rados ls --pool mypool | grep -v rbd_data rados ls --pool mypool | grep rbd_dataRBD的块数据对象命名通常带有rbd_data前缀。如果一批rbd_data对象对应的镜像已经不存在了那它们就是孤儿对象。对孤儿对象可以用以下命令删除rados rm -p mypool object_name但这里我强烈建议不要手动一个个删低效且容易误删。更稳妥的方式是用scrub机制让OSD自动清理ceph pg scrub pgid或者对pool做一次深度scrubceph osd pool scrub mypoolscrub会把内存中的对象信息和OSD上的实际对象做比对发现多余对象后触发清理。这个方法比手动删更安全不会破坏正常的RBD元数据。4. 验证空间是否释放别被ceph df的数字骗了很多人反映trash也清了快照也删了为什么ceph df看到的USED还是没变化这里要搞清楚ceph df显示的数据层次。4.1 区分总容量和实际使用ceph df的输出有两大部分GLOBAL行和POOL行。GLOBAL里的RAW USED表示整个集群所有OSD实际占用磁盘的大小包括所有pool的对象、副本、内部元数据等。POOL行里的USED则只统计pool内的逻辑对象大小不包含副本。删除RBD镜像后pool的USED会先下降但RAW USED可能延迟变化。原因是OSD在完成删除对象操作后还可能有一些额外开销比如日志、内部元数据更新、wal文件等。这些不会瞬间全部反映到RAW USED里。如果你想看更实时的变化可以用ceph osd df tree这个命令能看到每个OSD的具体使用量。删除操作触发后你可以观察对应OSD的USED值是否在慢慢回落。如果某个OSD的USED始终不变且trash和快照都已经处理完那有可能存在PG分布不均的问题或者OSD的删除队列被卡住了。4.2 估算预期释放的空间在删除前可以通过镜像的size和快照数量来估算预期释放空间。rbd info --pool mypool myimagerbd info里的size是逻辑容量并非实际占用。实际占用取决于镜像内部写入了多少数据块以及副本数。估算公式是实际释放空间 ≈ 镜像实际数据量 × 副本数比如一个镜像逻辑大小100G实际写入50Gpool是3副本则释放约150G。如果镜像包含多个快照每个快照都有自己的对象那要考虑快照占用的独立空间。这里有一个容易踩坑的点Ceph的压缩功能。如果pool启用了压缩通常基于zstd写进去的数据在底层可能小于逻辑数据量。这种情况下释放的空间会比预期少。不要因此怀疑操作失败先做数据量对比再下结论。4.3 最终确认命令排障结束后我通常用一条组合命令做最终确认ceph df | grep mypool rbd trash ls --pool mypool --all rados du --pool mypool | tail -n 5三条命令的输出应该同时满足trash列表为空pool的USED明显下降rados du的统计和pool USED基本一致如果满足这些条件那空间释放问题就是真正解决了。5. 常见问题与避坑心得这个主题我在群里和社区里被问过很多次整理几个典型问题当作排障速查表用。5.1 为什么rbd trash purge执行了还是一样最常见原因就是延迟删除配置。先确认ceph config get client.rbd rbd_trash_remove_delay如果值大于0等到足够时间后空间才会释放。另外如果trash里的镜像仍被watchpurge会跳过它需要先处理watcher。5.2rbd rm命令卡住不动这种情况通常发生在镜像正被使用或者有大量快照。执行rbd rm时它会尝试停掉watch并通知所有客户端如果客户端无响应命令就会一直等。这时候先在trash里看镜像状态rbd trash ls --pool mypool状态显示watched就按前面说的处理watcher显示removing则检查后台是否有删除进程在跑ceph tell osd.* ceph_osd_pg_scrub如果确认删除进程确实卡死可以尝试重启相关OSD进程让对象删除请求重新调度。不过在生产环境操作OSD前一定要确认业务容忍度优先在低峰窗口执行。5.3 为什么删除后空间不升反降这种情况我也遇到过通常不是删除导致而是删除操作触发了大量对象的副本平衡。删除对象后OSD会重新平衡分布可能触发数据迁移或者backfill期间磁盘写入会增加导致USED看起来反而升高了。等平衡完成空间才会正常回落。所以看到短时间内的上升不用慌观察一段时间。5.4 关于对象命名空间的坑RBD镜像在pool里不仅有数据对象还有元数据对象。rbd ls看不到的隐藏命名空间里有rbd_directory、rbd_info、rbd_header等对象。手动清理时如果误删了这些元数据对象RBD镜像会直接损坏。所以再次强调不要手动用rados去删rbd_开头的对象。5.5 恢复误删的RBDtrash机制的存在让误删恢复成了可能。只要镜像还在trash里且未被purge就可以通过以下命令恢复到原位置rbd trash restore --pool mypool myimage --image newname这个操作实际执行过恢复后镜像数据完整可用。这也是为什么我不建议你一上来就purge如果只是确认误删先restore比重建虚拟机恢复数据要靠谱得多。6. 遗留细节pool级配置和长期优化建议处理完当前问题后建议从机制层面做一些长期调整减少未来再遇到同类问题的概率。对于测试环境或临时项目使用的pool可以将延迟删除时间设置为0让删除操作立即清理ceph config set client.rbd rbd_trash_remove_delay 0对于生产环境建议保留延迟删除时间比如1小时或24小时。误操作时有后悔药可以吃不差这几个小时的空间。同时把trash巡检加入日常监控脚本定期检查是否有堆积的trash项目。对克隆使用比较多的场景建议在删除父镜像前先产出完整的clone依赖清单并制定逐层删除计划。这可以通过脚本实现一句话总结就是先删子、再删父、最后清trash。好在Ceph的这套机制都是从数据安全角度出发的虽然让我多排查了很多次但至少没出现过误删无法恢复的事故。以我个人维护集群的经验处理这类问题最大的成本不是命令不会敲而是定位不到阻塞点。只要按照trash → watch → 快照 → 孤儿对象这条链路走大部分问题都能快速收尾。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑