【Ceph RADOS】BlueStore 写路径:min_alloc_size、deferred/WAL、checksum 与压缩
内容提要
本文介绍Ceph BlueStore写路径,涵盖queue_transactions()到aio完成的流程,重点分析直写与deferred两条分叉路径。直写适用于大块新分配,数据先落盘再提交元数据;deferred用于小写或覆盖,先提交KV再异步落盘。文章还讨论min_alloc_size配置、checksum计算时机、压缩处理及deferred路径的带宽竞争问题。
延伸解读
min_alloc_size 的版本差异与运维陷阱
min_alloc_size 默认值随版本变化:Mimic 及更早 HDD 为 64 KiB,SSD 为 16 KiB;Octopus 起 SSD 改为 4 KiB;Pacific 及以后统一为 4 KiB。该值在 OSD 创建时烘焙,事后修改配置或升级发行版不会改变已有 OSD。混布不同版本创建的 OSD 会导致空间统计异常,需用 `ceph osd metadata` 核对,不一致时只能销毁重建。
deferred 路径的崩溃安全与双写代价
deferred 路径通过先提交 RocksDB 事务(包含 deferred 记录和 onode)再异步落盘,保证崩溃时数据不丢失。但这也引入了受控双写:数据先写入 WAL,再由后台 finisher 复制到数据盘。积压时前台会被拖住,需关注 `bluestore_throttle_deferred_bytes` 等参数。与 FileStore 的全量双写不同,deferred 仅用于小写和覆盖写。
压缩与 checksum 的交互
BlueStore 在压缩后计算 checksum,因此 csum 校验的是压缩后的字节,而非原始数据。这意味着解压后的数据完整性需依赖上层(如 PG log 或 scrub)保证。压缩通常不用于 deferred 路径,因为小写可能触发读-改-写,代价过高。配置压缩算法时需权衡 CPU 开销与空间节省,例如 zstd 适合冷数据,lz4 适合 NVMe。
deferred 路径的带宽竞争与可观测性缺口
deferred_finisher 的后台写与前台写共享数据盘带宽,在 HDD 场景下易导致写延迟抖动。Ceph 虽有 `bluestore_deferred_batch_ops` 等参数调节,但 mClock 调度器无法直接控制 deferred 带宽。此外,当前 perf dump 无法直接观测 deferred 队列深度和延迟分解,排障时需结合日志推断,这是 Squid 时代的开放问题。
Q&A
Ceph BlueStore 写路径中,直写和 deferred 两条路径分别适用于什么场景?
直写适用于新分配的大块数据(≥ min_alloc_size),数据先落盘再提交元数据;deferred 适用于小写(< min_alloc_size)或就地覆盖写,先提交 KV 再异步落盘。
bluestore_min_alloc_size 默认值是多少?不同版本有区别吗?
在 Pacific 及以后(含 Squid)默认值为 4 KiB;Mimic 及更早 HDD 默认 64 KiB、SSD/NVMe 默认 16 KiB;Octopus 时 SSD/NVMe 默认改为 4 KiB。该值在 OSD 创建时烘焙,事后修改配置不会改变已有 OSD。
BlueStore 的 deferred 写路径是如何保证崩溃一致性的?
deferred 路径先将数据作为 deferred 记录和更新后的 onode 一起通过 RocksDB 原子提交,然后后台异步写入裸盘。崩溃时,若 KV 已提交但数据未落盘,mount 时重放 deferred 记录;若数据已落盘但 KV 未提交,则写操作视为未发生。
BlueStore 中 checksum 是在什么时候计算的?它校验的是压缩前还是压缩后的数据?
checksum 在数据写入前计算,直写路径在 aio 提交前,deferred 路径在构造 deferred 载荷时。若启用压缩,checksum 在压缩后计算,校验的是压缩后的数据。
BlueStore 支持哪些压缩算法?各有什么特点?
支持 snappy(压缩快,解压更快,压缩率一般)、zlib(压缩率好,CPU 开销高)、lz4(速度与压缩率折中,适合 NVMe)、zstd(高压缩率,支持级别 1-22,适合冷数据)。
deferred 路径的带宽竞争问题是什么?Ceph 如何应对?
deferred_finisher 后台写与前台写竞争数据盘带宽,尤其在 HDD 上导致写延迟抖动。Ceph 通过 bluestore_deferred_batch_ops 和 bluestore_max_deferred_txs 等参数调节,但 mClock 调度器对 deferred_finisher 的带宽没有直接控制,该问题在 Squid 时代尚无系统性解法。
BlueStore 写路径中,COW(写时复制)是如何工作的?
当覆盖共享 blob(引用计数 > 1)时,不能就地修改,而是分配新的物理区间,将新数据直写到新区间,更新本对象 extent_map,原共享 blob 引用递减,为零时归还 Allocator。