Fencing 101
文章目录
前言
在分布式系统中,我们常用 Lease(租约) 控制某个节点对资源的独占访问。然而,当网络分区或节点故障后,“过期”节点仍可能持有旧的访问权限并发起非法写入,这就引入了一个严重问题:脑裂(Split Brain)写入。
为防止这种情况发生,Fencing(防越权机制) 被设计出来,作为 lease 的“护城河”,保障系统一致性与安全性。
定义
wiki 上未直接定义 fencing,但在分布式系统设计中,fencing 常被定义为:
Fencing is a mechanism to prevent outdated or unauthorized nodes from accessing a resource after their lease has expired or ownership has changed.
一句话:Fencing 是一种防止“过期节点”继续访问资源的保护机制。
工作原理
一句话:每次 lease 分配时生成一个递增的版本号,只有持有最新 fencing token 的节点才能访问资源。
典型流程如下:
- 每次 lease 分配/续约时,协调者生成一个唯一递增的 fencing token;
- 节点在访问资源时必须携带该 token;
- 资源服务端(如存储系统)在处理请求前检查 token 是否为最新;
- 如果 token 过期或无效,拒绝处理,防止旧节点写入。
此机制不依赖时钟同步,天然抗网络分区,是解决“旧节点写穿”问题的关键。
属性与指标
关注的 fencing 属性与指标如下:
-
Fencing Token 单调递增性 保证每次 token 都比上一次大,避免重用。
-
Token 分发机制 通常由中心协调者(如 etcd/Zookeeper)统一生成和分发。
-
资源端校验能力 后端必须支持对 token 的解析与校验逻辑。
-
防止 ABA 问题 防止“旧 lease -> 新 lease -> 旧 lease”导致错误重入。
-
无依赖于时钟精度 fencing token 本质为逻辑版本号,不依赖机器时钟。
类型
根据 token 类型分
-
数值型 token(如递增整数) 最常见方式,每次 lease 分配时递增。例如 etcd 使用 revision。
-
时间戳型 token 使用分配时刻作为 token,但需注意时钟漂移问题。
-
UUID型(唯一标识符) 虽不能比较新旧,但可用于检测不同实例。
根据校验策略分
-
客户端校验型 客户端先读出当前 token,再判断是否自己仍持有有效权限。
-
服务端校验型(推荐) 服务端保存最新 token,拒绝处理老 token 的请求。
fencing 与程序关系
程序中使用 fencing 的方式通常如下:
-
分布式锁服务结合 fencing 比如基于 Zookeeper ephemeral node + fencing token 控制写入权。
-
存储系统防止旧主写入 比如 HDFS 的 NameNode 使用 fencing 来保护数据块元数据写入。
-
任务调度系统防止重复执行 调度器判断执行者是否仍持有有效 lease token,防止旧任务重复执行。
编程实践要点:
- 资源服务端必须内建 fencing token 校验逻辑;
- 在 lease 获取时记录 token,所有访问必须带 token;
- 注意 token 回收与过期处理,防止内存泄漏。
常用 fencing 场景/产品
-
etcd + fencing token etcd 事务 revision 号可作为 fencing token,天然递增。
-
Zookeeper + 顺序节点 通过顺序 ephemeral node 实现 fencing,最小序号即为持有者。
-
HDFS + fencing script Secondary NameNode 激活前执行 fencing 脚本(如强制 unmount)。
-
Kubernetes Lease API + fencing controller-manager 使用 fencing 确保只有最新 leader 可操作资源。
-
Google Chubby Lock Service 分配 lock ID 作为 fencing token,用于保证唯一写者。
文章作者 沉风网事
上次更新 2018-10-25