CephFS 合规存储
# CephFS 合规存储
# 项目定位
CephFS 合规存储的目标不是简单增加一个文件属性,而是把“文件进入保护期后不可改、不可删、按策略受控解封”的能力下沉到文件系统控制面。面向监管留存、档案归档、日志留存等不可篡改场景,系统不能只依赖业务侧流程或外围平台约束,需要由 CephFS 元数据控制面直接裁决写入、修改、删除和解封行为。
- 我的职责:负责需求拆解、方案设计和核心链路开发,覆盖客户端、协议层、MDS 控制面、OMAP 持久化和审计链路。
- 核心结果:形成目录级 WORM 策略、生命周期状态、逻辑 WORM 时钟、双侧访问控制、审计追溯和重启恢复的能力闭环。
- 技术栈:
C++、CephFS、MDS、libcephfs、Python、OMAP
# 方案总览
核心设计围绕以下问题展开:
- 目录级策略如何稳定作用到子文件。
- WORM 元数据放在哪里,如何和 inode 生命周期保持一致。
- 文件保护期、过期、追加写等状态如何流转。
- 保护期判断如何避免被本地系统时间影响。
- 客户端缓存路径和 MDS 服务端裁决如何同时覆盖。
- 多 MDS 场景下逻辑时钟和策略状态如何保持一致。
- 大量文件同时到期时,如何避免冲击 metadata IO。
- 审计记录如何落盘、导出和用于合规追溯。
# WORM 元数据模型
WORM 元数据主存储挂载在 MDS inode 元数据结构中,作为 inode_t 的一等字段,而不是放在普通 xattr 中。这样可以让权限判断、状态流转和 inode 元数据持久化保持同一条链路,减少绕过和状态不同步风险。
核心字段包括:
_state:标识当前 WORM 状态,例如未保护、保护中、已过期等。_max_protection:允许配置的最长保护期。_min_protection:允许配置的最短保护期。_default_protection:未单独配置时使用的默认保护期。_auto_commit:控制 WORM 状态是否自动提交。
策略入口目录、逻辑时钟和审计记录等全局数据通过 OMAP 持久化,支持 MDS 重启后的恢复加载。
# 生命周期状态机
WORM 生命周期状态机用于描述目录或文件从未保护到保护中、延长保护、过期可编辑、过期不可编辑、追加写等状态的流转。
状态机的关键点是:权限判断不能只看 _state,还需要结合 WORM 逻辑时钟和文件到期时间。这样可以做到“到期即逻辑生效,后台状态推进最终一致”:文件刚过期时,MDS 可以立即按过期状态处理权限,后台再异步推进状态和统计信息,避免大量到期文件同时触发元数据写放大。
# 逻辑 WORM 时钟
WORM 是强时间语义的状态控制,不能直接依赖节点本地系统时间。否则用户或环境修改系统时间后,保护期判断可能提前或延后,破坏不可篡改语义。
项目中单独设计 WormClock:
- 维护全局逻辑 WORM 时间
worm_time。 - 将逻辑时间和过期策略持久化到元数据池中的
worm_clock对象。 - 通过定时器周期推进,默认每 1 秒 tick。
- rank 0 负责校准并落盘,其他 rank 跟随递增。
- 当节点长时间宕机导致逻辑时间落后时,基于持久化基准时间和单调时钟做逐步追赶,避免直接跳变导致文件提前过期。
这个设计把保护期判断从“机器时间”转为“文件系统内部业务时间”,提升多节点和异常场景下的一致性。
# 客户端与 MDS 双侧控制
只在 MDS 侧拦截不足以形成完整闭环。客户端可能基于缓存或协议差异提前发起部分操作,如果没有客户端侧状态感知,某些路径会产生绕过风险。
因此访问控制分为两层:
- 客户端快速拒绝:MDS 在
MClientCaps、MClientReply等消息中同步 inode 的worm_info,客户端拿到服务端认可的 WORM 状态后,可以提前拒绝明显非法的写路径。 - MDS 最终裁决:在服务端关键元数据路径中统一校验 WORM 状态,覆盖
open、write、truncate、unlink、rename、link、setattr等操作。
关闭 WORM 功能时,热路径主要增加内存读取和状态比较,尽量降低对原有 metadata IO 的影响。
# MDS 模块拆分
MDS 侧以 WormManager 作为统一调度入口,内部拆分为 4 个核心模块:
WormClock:维护逻辑 WORM 时间和过期策略,为状态机提供统一时间基准。WormInfo:维护被设置为 WORM root dir 的目录集合,负责策略入口目录登记。WormList:维护待推进 inode 集合,周期扫描并推进生命周期状态,生成自动审计记录。WormRecord:记录 WORM 操作审计日志,包括时间、inode、文件名、操作类型和结果码,按天分片写入 OMAP。
这种拆分让 MDS 对外只暴露统一入口,内部按职责隔离逻辑时钟、策略入口、状态推进和审计追溯,便于后续定位问题和扩展能力。
# 接口与管控链路
项目扩展了 libcephfs、Python 绑定层和 CephFS MDS 操作码,给管理平台提供 WORM 配置和运维接口。
接口能力包括:
- 新增、修改、删除、查询 WORM 策略。
- 获取和设置 WORM 逻辑时钟与过期策略。
- 查询指定目录或文件的 WORM 元数据。
- 特殊场景下由超级管理员执行受控后台删除。
- 导出审计记录用于合规追溯。
请求链路上,协议层补充 WORM 相关参数,MDS 侧完成策略变更、状态更新、审计记录和持久化,客户端侧同步服务端认可的状态用于快速判断。
# OMAP 持久化与审计追溯
OMAP 主要承载三类数据:
worm_clock:逻辑时钟和过期策略。worm_info:WORM 根目录集合。worm_record:审计记录,按天切分对象,记录操作类型、结果、目标 inode 和文件名等信息。
审计记录覆盖策略变更、时钟调整、自动状态切换、删除拒绝等关键路径。对于大量导出场景,需要做导出限流,避免审计查询影响正常业务请求。
# 多 MDS 一致性与恢复
多 MDS 场景下,每个 MDS 负责自己权威目录下的 WORM 管理,逻辑时钟以 rank 0 为基准。
- rank 0 维护并持久化权威 WORM 时钟。
- 非 rank 0 MDS 通过心跳获取 rank 0 的权威信息。
- 非 rank 0 MDS 首次加载或状态缺失时,从 RADOS 重新加载持久化数据。
- 策略和状态变更随 inode 权威归属处理,避免每个请求都做跨 rank 强同步。
这个方案优先保证热路径开销可控,同时通过持久化数据和心跳传播维持业务时间基准的一致性。
# 大量文件到期处理
极端场景下,可能存在大量文件在同一时间进入过期状态。如果后台立即对每个 inode 发起元数据变更,会冲击 MDS 和底层元数据池。
处理策略是:
- 权限判断即时生效:请求到达时,MDS 结合到期时间和 WORM 逻辑时钟判断文件是否已过期。
- 状态推进后台处理:状态转换、统计更新和审计记录可以延迟推进。
- 后台任务限速:降低过期处理优先级,避免阻塞正常 metadata IO。
- 批量持久化:聚合一批 inode 后再落盘,减少底层 OMAP / 元数据写压力。
这使“用户看到的权限语义”与“后台物理状态更新”解耦,保证合规语义先成立,再保证状态最终一致。
# 关键设计取舍
# inode_t 与 xattr 选型
最终选择把 WORM 元数据放入 inode_t,核心原因是 WORM 属于文件系统层面的强约束,而不是普通扩展属性。
inode_t 方案的优势:
- 加载 inode 时即可解析 WORM 信息,无需额外查询。
- WORM 状态与 inode 元数据同步持久化,状态一致性更强。
- 权限控制更严格,降低通过普通属性路径绕过的风险。
- 高频权限判断路径更稳定,适合 metadata IO 热路径。
代价是需要处理编码版本兼容、字段扩展和 inode 基础结构变更影响。相比 xattr 的扩展灵活性,项目更优先选择性能、语义和安全边界。
# 逻辑时钟与系统时钟
系统时钟简单,但不可控;逻辑时钟复杂,但能给 WORM 提供独立业务时间基准。该项目选择逻辑 WORM 时钟,是为了避免本地时间被修改、节点宕机或多 MDS 时间差异导致保护期判断失真。
# 客户端预判与服务端裁决
客户端预判用于减少无效请求和绕过风险,MDS 裁决用于保证最终一致的安全边界。两者同时存在,才能覆盖缓存、协议和服务端关键路径。
# 当前边界与后续优化
- 内核客户端场景:若内核挂载方式需要启用 WORM 特性,需要部署支持该数据结构的指定版本 Ceph 内核组件;未启用 WORM 时可保持原有兼容。
- 审计防篡改:当前审计记录写入 OMAP,具备追溯能力,但底层有权限人员仍可能修改 OMAP,后续可增强审计记录自身的防篡改能力。
- 审计查询效率:当前按天分片降低扫描范围,但失败记录和成功记录混在同一对象中,细粒度查询仍依赖导出后筛选,后续可增加二级索引或更细粒度分片。
- 管理平台封装:底层接口已经提供策略配置、时钟管理和审计导出能力,后续可继续增强页面化操作、权限隔离和风险提示。