Vadim Yatsenko:PolarFS:磁盘 Paxos 读写租约,让共享存储远离脑裂

💡 原文英文,约2500词,阅读约需9分钟。
📝

内容提要

PolarDB 采用计算与存储分离架构,多个节点可访问同一共享块设备,但仅允许一个节点以读写方式挂载,否则会导致数据损坏。原代码只用本机 fcntl 锁防止同机二次挂载,跨主机仍可能脑裂。为此 PolarFS 新增磁盘 Paxos 租约:每台主机在 paxos 文件中占用一个 512 字节扇区,通过准备、验证、获取、冲突检查的两阶段投票进行仲裁,租约每秒续期;续期失败则分层自隔离(abort、定时 SIGKILL、内核看门狗重启),确保至多一个写者。

🔎

延伸解读

租约依赖时钟同步,NTP 漂移是隐性风险

PolarFS 的租约用 CLOCK_REALTIME 记录续期时间,并通过 paxos_clock_skew_max(默认 2 秒)容忍时钟偏差。这意味着集群必须保持 NTP 同步:若某主机时钟漂移或回拨,可能把存活持有者误判为过期,或把陈旧记录误判为新鲜。文章明确将“主机时钟在允许偏差内”列为保证成立的前提之一,运维需监控时钟健康。

自隔离是最后防线,但依赖内核看门狗真正生效

续期失败时,节点依次 abort、定时 SIGKILL、可选内核看门狗重启。文章强调若无法武装 kill 定时器,挂载会拒绝租约,因为日志线程自身卡死时无法自我了断。但内核看门狗需启用 paxos_watchdog_enable 并打开 /dev/watchdog,若未配置,内核级挂起时只能依赖前两层。读者应确认该选项在部署中是否开启。

接管最长等待一个租约窗口,故障切换有明确延迟

新节点发现存活持有者时不会立即放弃,而是每秒轮询其扇区,最多等待一个租约时长(默认 30 秒)加时钟偏差。若时间戳推进则返回 -EBUSY;若扇区清零则重新检查;若时间戳停滞整个窗口则判定死亡并接管。这一设计避免逐个主机顺序等待,但也意味着故障切换存在可预期的秒级延迟,需与上层故障转移策略配合。

升级无需迁移,但备份恢复需重置租约扇区

每主机扇区在既有部署中始终为零,升级集群看到空扇区即运行新协议,降级也安全,因为旧代码不读这些扇区。唯一例外是 PBD 副本:fscp 和 chunk 备份/恢复会逐字复制 paxos 块,包括租约记录,因此恢复后需执行重置清除。新增的 pfs lease 子命令可打印各主机租约状态,便于 DBA 区分“挂载失败”与“某主机持有租约但未续期”。

❓

Q&A

PolarFS 为什么需要磁盘 Paxos 租约?

PolarDB 采用计算存储分离架构,多个计算节点可访问同一共享块设备,但只允许一个节点以读写方式挂载,否则会导致数据损坏。原有代码仅用本机 fcntl 锁防止同机二次挂载,跨主机仍可能发生脑裂。磁盘 Paxos 租约在共享磁盘上写入可续期的锁记录,确保至多一个写者。

PolarFS 的租约是如何获取的?

获取读写租约是一个两阶段、基于 ballot 的协议:1) 检查所有主机扇区,若有活跃 RW 记录则返回 -EBUSY;2) 准备阶段写入 FL_PREPARE 和 ballot;3) 验证阶段再次读取,若有其他主机的活跃 RW 记录或更高 ballot 则退出;4) 获取阶段写入 FL_RW;5) 冲突检查再次读取,最高 ballot 获胜。每一步必须在之前写入的记录仍活跃时完成。

租约续期失败时节点如何自我隔离?

租约每秒续期。续期失败一个租约周期后,日志线程调用 abort() 终止自身;同时一个 POSIX 定时器在日志线程停止喂狗时发送 SIGUSR2,处理函数写入消息并触发 SIGKILL;若启用内核看门狗,节点在每次续期时喂 /dev/watchdog,内核挂起时看门狗重启机器。分层自隔离确保失去续期能力的节点停止写入。

Paxos 文件中的主机记录包含哪些关键字段?

每个主机在 paxos 文件中占用一个 512 字节扇区,结构体 pfs_host_record_t 包含:hr_magic(魔数)、hr_flags(标记 FL_PREPARE 或 FL_RW)、hr_host_id、hr_generation(崩溃恢复后递增)、hr_timestamp(最后续期的 CLOCK_REALTIME 秒数)、hr_mbal(承诺的 ballot)、hr_bal(接受的 ballot)、填充字节和 hr_checksum(crc32c 校验和)。

新节点发现现有持有者时如何处理?

新节点不会立即放弃,而是每秒轮询持有者扇区,最多等待一个租约周期(默认 30 秒加时钟偏差允许值)。若时间戳前进,持有者存活,返回 -EBUSY;若扇区被清零,持有者已干净卸载,重新检查并继续;若时间戳在一个租约窗口内停止移动,则假定持有者死亡,重新检查并接管。

该租约机制有哪些前提假设和成本?

前提假设:主机时钟保持在配置的偏差允许范围内(默认 2 秒),且被隔离的持有者确实停止写入。成本:挂载时额外几次扇区读写,挂载期间每秒一次扇区写入,接管时最多等待一个租约周期(默认 30 秒加偏差允许值)。相比数据损坏的代价,这些成本很小。

🏷️

标签

➡️

继续阅读