很多人把分布式锁当成一把"万能保险",只要在代码里先去抢一把锁,再去做扣减库存、写文件、改共享状态这种关键操作,就以为这段逻辑从此安全了。这种想法在单机或者网络一切正常的环境里或许勉强成立,但只要系统进入分布式部署、又遇到网络分区,这把锁就可能从"保险"变成"假保险"。所谓网络分区,就是集群里的节点之间、节点与协调服务之间出现了不对称、不可预期的断开,此时原本被认为"独占"的资源,实际上可能同时被两个或更多节点持有。本文想说的核心结论是:在网络分区下,分布式锁默认是不可靠的;要让它真正可用,必须依赖租约(lease)加自动过期,再叠加上 fencing token 这层递增令牌校验,而不是天真地认为"我拿到了锁就安全"。
最常见的误解是把分布式锁等同于单机里那种"拿到就独占"的互斥量。在单进程里,一把锁意味着同一时刻只有一个线程进入临界区,这个假设是成立的,因为线程调度由操作系统严格保证,不会出现两个线程同时持有一把互斥量的情形。但分布式系统的前提完全不同:节点之间是靠不可靠的网络通信的,节点之间的状态不是由操作系统内核统一调度的,而是各自独立运行、各自对"我还持有锁吗"这件事做判断。
于是出现了第一个认知偏差:把"成功获取锁"这个一次性事件当成了"持续持有锁"的保证。实际上,在分布式环境里,获取锁的那一刻只代表协调服务在那一刻同意了你的请求,并不代表之后你真的能一直独占。网络会抖、节点会卡、协调服务会重新选主,任何一环出问题,原本的独占关系都可能被打破。把一次性授权当成长期保证,是后面所有脑裂问题的根源。
第二个认知偏差是相信"锁超时时间我可以设得很长,长到业务一定跑完"。这种做法看似省事,其实是在用"更长的危险窗口"去赌"业务永远不会慢"。一旦真的出现进程卡顿、Full GC、容器被抢占调度,长超时反而让冲突窗口变得更大,问题更隐蔽。
第三个认知偏差是把锁和临界区真正的安全性混为一谈。即便锁本身是完美的,使用锁的那段代码是否真的把"写操作"限制在了"持锁者最近一次授权"的范围内,又是另一回事。不少线上故障不是锁没抢到,而是旧持锁者被网络"遗忘"后,它的迟到写操作覆盖了新持锁者已经提交的结果。
讨论分布式锁之前,得先说清楚"网络分区"在工程上到底是什么样子。教科书里常画成网络被一刀切成两半,左边和右边完全不通。但真实的故障远比这复杂:它可能只是节点 A 到协调服务这一条链路抖动丢包,而节点 B 到协调服务依然正常;也可能是节点之间还能通、但都连不上多数派;还可能是节点 A 自己因为 CPU 打满、磁盘 IO 卡死而"活着但没反应",在协议层表现得很像失联。
这种不对称,正是分布式锁最危险的场景。设想一个三节点的协调集群加两个业务节点 A 和 B。A 和业务集群的多数派失联了,但在 A 自己的视角里,它可能只是以为"网络有点慢",并不知道协调服务已经把它判为失联。与此同时,B 仍然和协调服务正常通信,于是 B 可以正常申请锁。结果就是:A 还以为自己持锁,B 也成功持锁,两个节点同时进入了同一个临界区。这就是脑裂,而它并不是极端小概率事件,而是分区故障下相当自然的后果。
还有一个容易被忽略的点:分区不是"一直断",而是"断一阵又恢复"。恢复之后,那个在分区期间"被遗忘的持锁者"带着它之前读到的一份旧状态回来了,它要继续把没写完的操作写完。如果此时新持锁者已经基于更新的状态做了修改,旧持锁者的迟到写入就会把数据改坏。很多数据错乱不是发生在分区那一刻,而是发生在分区恢复之后那几秒。
把脑裂拆开看,它的触发链条其实很清晰。第一步,节点 A 通过协调服务拿到锁,锁里记录着"当前归属 A、过期时间 T"。第二步,A 与协调服务之间的网络发生分区,或者 A 自身发生长时间停顿,导致协调服务在 A 不知情的情况下,因为锁到达过期时间而把它释放。第三步,节点 B 此时来申请锁,协调服务发现锁已释放,便把锁授予 B,记录更新为"归属 B"。第四步,A 从停顿或网络抖动里恢复,它本地仍然认为"我持有锁",于是它继续进入临界区执行写操作。此刻 A 和 B 都在写同一份共享资源,互斥彻底失效。
这里的关键不在"谁先拿到",而在"拿到之后能不能被悄无声息地剥夺"。如果锁没有自动过期机制,A 永远不会被剥夺,B 永远拿不到,那反而不会出现双持;但那样又会带来另一个灾难:A 真的崩溃了,锁永不过期,整个系统被一把死锁卡死。所以"锁必须能过期"是刚需,但"能过期"本身又直接打开了脑裂的口子。这就是为什么单靠一把会过期的锁还不够,必须再引入 fencing token 来堵住"旧持锁者的迟到写"。
还需要区分一种情况:并不是所有重复持锁都来自网络分区。进程被操作系统暂停(比如容器调度、内存压力触发的 swap、磁盘抖动),同样会让一个节点"逻辑上失联"而"物理上还活着"。从协调服务的视角看,这和分区没有区别,效果也完全一样。所以讨论分区下的锁安全,要同时把"通信分区"和"计算停顿"都算进来,它们共享同一套失效模型。
说到计算停顿,就绕不开垃圾回收。使用带有自动内存管理运行时(例如某些主流 JVM 语言)的服务,在 Full GC 或者长时间的 Stop-The-World 阶段,应用线程会被整体暂停,可能持续数百毫秒甚至数秒。这段时间里,这个节点对外完全无响应,但它既没有崩溃,也没有和网络真的断开——它只是"卡住了"。
从锁协调服务的角度,这个节点的心跳停了、租约到点了,于是锁被释放并授予他人。等 GC 结束,节点"醒"过来,它本地缓存的"我持有锁"状态并未被刷新,于是它继续去写共享资源。这和真正的网络分区造成的脑裂在机制上完全一致,只是起因不同。很多工程师只在脑海里防"网线被拔掉",却忘了"GC 长暂停"就是一种更常见的软分区。这也是为什么正确做法不能依赖"持锁节点永远及时响应",而要让每一次写操作都能独立校验自己是不是合法的当前持锁者。
更麻烦的是,GC 停顿往往发生在负载高、请求集中的时刻,而那恰恰也是最需要锁发挥作用的时刻。换句话说,锁最容易失效的窗口,正是系统压力最大的窗口。如果架构假设锁在压力之下依然可靠,那这个假设在最危险的时候反而最脆弱。
解决脑裂的第一步,是让锁带有一个租约(lease)。租约本质上是一段有时限的授权:协调服务授予锁时,附带一个过期时间;超过这个时间,锁自动失效,不需要原持锁者主动释放。这样即使持锁者崩溃、卡死、或者与多数派失联,锁也不会永远被占用,系统不会因为一个死锁而停摆。
租约过期时间怎么定,是个权衡。设得太短,正常业务的临界区可能还没跑完锁就过期了,引发"持锁者还在干活却被剥夺"的提前失效;设得太长,发生分区时冲突窗口被拉大,双持的时间更长、破坏更大。经验上的做法是:租约时长应该明显大于正常临界区的执行时间,但又要远小于你愿意容忍的"失联节点可能造成的破坏时长"。很多团队会用"业务正常耗时的若干倍"作为下限,再结合故障恢复目标倒推上限。
另一个重要细节是"续租"机制。长任务不能一次性申请一个超长租约,而应该用一个独立的看门狗(watchdog)线程,在租约到期前周期性地向协调服务续期,前提是节点仍然健康、仍然与多数派连通。一旦节点失联或卡死,续租停止,租约自然过期。这样就把"锁的存活"和"节点的真实健康"绑在了一起,而不是绑在"节点曾经拿到过锁"这件事上。换句话说,租约把"我是否还活着且连通"变成了"我是否还持锁"的充要条件之一。
但这里必须强调一个边界:租约解决了"锁能释放"的问题,并没有解决"旧持锁者醒来后迟到写"的问题。即使有完美的租约和续租,前面描述的 A 醒来后继续写、覆盖 B 的场景依然可能发生,因为 A 本地的"我持锁"判断在它醒来那一刻还没被刷新。这需要第二道防线。
fencing token(有时也叫 fencing 令牌、单调递增令牌)是堵住迟到写那道缺口的标准做法。它的思路非常朴素:协调服务在每次成功授予锁时,都返回一个严格单调递增的令牌值,例如第一次给 1,第二次给 2,第三次给 3,以此类推。所有需要保护的共享资源(比如一个存储系统、一个文件、一张表)在内部记住"当前已接受的最大令牌值"。
当持锁者要去写共享资源时,它必须把这次拿到的 fencing token 一并发给存储后端。存储后端收到写请求后,先比较:如果请求里的令牌小于等于它已经见过的最大令牌,就直接拒绝这次写;只有当令牌严格大于已见最大值时,才接受写,并更新自己记录的最大令牌。这样一来,分区恢复后醒来的 A 带着旧令牌(比如 1)去写,而此时 B 早已用令牌 2 成功写入过,存储后端会拒绝 A 的迟到写,因为 1 不大于 2。旧持锁者的迟到写被自动丢弃,数据不会被覆盖。
fencing token 之所以有效,是因为它把"互斥的正确性"从"持锁者主观判断是否持锁"转移到了"存储后端客观校验令牌顺序"上。锁服务可能会误判、网络可能会欺骗、节点可能会记忆错乱,但存储后端那一条"只接受更大令牌"的规则是机械且可靠的。换句话说,fencing 把安全性下沉到了真正会发生写操作的地方,而不是停留在抢锁的环节。
这一点也解释了为什么"fencing token"比"锁自动过期"更进一层:过期解决的是"锁能被回收",fencing 解决的是"回收之后旧持有者的写不会污染新状态"。两者必须配合使用,缺一不可。只有租约没有 fencing,会留下迟到写漏洞;只有 fencing 没有租约,旧节点永不失效、令牌永不前进,新节点拿不到更大的令牌,系统可能卡死。
| 机制 | 分区下表现 | 适用 | 注意 |
|---|---|---|---|
| 无租约锁 | 持锁者失联后锁永不过期,崩溃即死锁;若强行长期持有又会在分区时造成双持,无自动回收机制 | 几乎不适用于生产环境 | 既可能死锁,又可能在分区下脑裂,必须带过期 |
| 带租约锁(仅租约) | 分区下可自动回收,避免死锁,但旧持锁者恢复后的迟到写仍可能覆盖新状态 | 短临界区且能容忍极低概率迟到写的场景 | 必须再叠加 fencing token 才能真正防迟到写 |
| fencing token | 存储层按令牌严格大于才接受写,旧持锁者醒来后的迟到写被直接拒绝 | 所有需要真正写安全的共享资源操作 | 所有写入口都要校验令牌,不能留旁路 |
| 基于共识的锁后端 | 仅与多数派连通的一侧可授权,降低双授概率,但不替代 fencing | 需要高可用、抗单点失效的锁服务 | 共识保证授予一致,不解决迟到写,仍需 fencing |
把 fencing token 落到工程里,有几个必须说清的细节。第一,令牌的递增必须由锁服务(或者一个具备线性一致性的协调组件)来保证,不能在客户端自己生成。如果每个节点各自从 0 开始数,那不同节点生成的令牌不可比较,fencing 形同虚设。令牌的来源必须是所有竞争者共享、且写操作能信任的唯一权威。
第二,令牌比较必须是"严格大于"而非"大于等于"。如果使用大于等于,那么同一个令牌的重复请求(比如网络重试)会被接受,这本是好事;但如果一个节点在拿到令牌后,因为重试把同一个令牌发了两次,而中间另一个节点已经用更大令牌写过,那么第二次的"等于"判断就会出错。一般做法是:存储后端记录最大令牌,请求令牌大于记录值则接受并更新,等于则按幂等重试处理,小于则拒绝。具体怎么对待"等于",取决于你的重试语义,但"小于必拒"是铁律。
第三,写操作必须把令牌作为请求的一部分,而不能依赖"我先抢锁、再单独写"这种分段信任。也就是说,临界区的保护性不能只体现在"抢锁成功"上,而要体现在"每一次实际写都携带并被校验令牌"。如果你的存储后端不支持在写接口里传入并校验令牌,那你就得在应用层自己实现这层校验,或者换用一个支持 fencing 语义的存储。
第四,fencing 只对"带令牌校验的写"生效。如果系统里还有别的路径能绕过令牌直接改共享状态(比如另一个不校验令牌的旧服务、一个手工改库的后台、一个没改造的批处理任务),那么 fencing 的防护就会被这些旁路打穿。所以落地 fencing 时,要确认所有写入共享资源的入口都被同一套令牌校验覆盖,否则就会像装了防盗门却留着窗户大开。
锁服务本身放在什么后端,直接决定了分区下的行为。最朴素的实现是依赖一个单点的存储(比如一个单机的关系库或者一个单机键值服务)来记锁状态和令牌。这种方案在链路正常时很简单,但单点一旦分区或宕机,整个锁服务就不可用:要么全部请求阻塞,要么全部放行,无论哪种都不是你想要的。单点后端把"锁可用"和"那一台机器健康"绑死,分区时它要么误杀正常请求,要么把锁彻底放空。
更稳妥的做法是让锁服务跑在一个基于共识的集群之上,例如依赖具备多数派机制的协调组件。这类组件在分区时,只有和多数派保持连通的那一侧能继续授予或回收锁,另一侧因为连不上多数派而自然失去授予锁的能力。这从协议层面减少了"两边同时授权"的概率。但要清醒:共识集群只能保证"锁服务不会同时授予两边同时成功",它并不能替你解决"旧持锁者醒来后迟到写"的问题——那仍然要靠 fencing token。共识解决的是锁授予的一致性,fencing 解决的是写操作的安全性,两者职责不同。
还要区分"锁服务基于共识"和"锁服务永远不脑裂"是两回事。即便底层是共识集群,只要存在上面说的计算停顿、客户端本地状态陈旧,旧持锁者迟到写的风险依旧存在。所以无论后端多强,fencing token 这一层都不应该省略。把后端升级当成"锁就安全了"的借口,是常见的过度自信。
讨论租约就绕不开时间,而分布式系统里最不可信的恰恰是时钟。很多早期锁实现把"锁过期"建立在各节点的墙上时钟比较之上:节点 A 记录"我在 10:00:00 拿到锁,十秒后过期",然后靠自己本地的时钟去判断过期。问题在于,不同机器的时钟会漂移,可能快几秒也可能慢几秒,NTP 同步也不是瞬时且绝对精确的。一旦节点 A 的时钟比协调服务慢,它就会在锁已经被回收之后,仍然以为自己持锁,从而继续写。
所以正确的租约实现,过期的判定应该主要由锁服务(协调方)一侧基于它自己的时钟来裁决,而不是由持锁者自己凭本地时钟宣布"我还在租约内"。持锁者能做的,是通过续租请求去"询问"锁服务自己是否还有效,而不是自己下结论。把过期裁决权集中到拥有单一时间视图的协调方,比让每个节点各自用本地时钟判断要可靠得多。
更进一步,如果系统要使用任何形式的"时间证明"(比如某个操作的时间戳排序),要意识到时钟漂移会直接破坏这种排序的正确性。这也是为什么 fencing token 用"逻辑递增计数器"而不是"时间戳"来表达先后顺序:逻辑令牌不依赖墙上时钟是否精确,只依赖锁服务按顺序发号,这个顺序是协调机制保证的,不受单机时钟漂移影响。能用逻辑顺序的地方就别用物理时钟,这是分布式正确性的一条经验法则。
说到这里,有人会问:既然分布式锁这么麻烦,为什么不直接用数据库的唯一约束或者事务来保证安全?答案是:它们解决的是不同层次的问题,最好的做法是让它们互补,而不是互相替代。
数据库的唯一约束(比如对某一列建唯一索引)能在存储层直接拒绝重复的写,它不依赖任何锁服务,也不需要租约和 fencing——这是它最大的优势。如果你的"临界区"本质上就是"插入一条带唯一键的记录"或者"更新某个固定主键的行",那么用唯一约束或带条件的更新语句(例如带版本号的乐观更新)往往比分布式锁更简洁、更可靠,因为它把正确性放在了真正发生写的地方。
但唯一约束覆盖不了所有场景。当临界区是一段复杂的多步操作、涉及多个资源、或者需要在内存里做计算再把结果写回时,光靠数据库约束就不够了,你仍然需要一个协调机制来串行化这段逻辑。此时更合理的架构是:用数据库事务/唯一约束兜住"最终写"的那一层安全,用分布式锁(带租约和 fencing)兜住"临界区串行化"的那一层协调。两者叠加,即使锁那一层出了偏差,底层的约束还能拦一道。
乐观锁(版本号/时间戳字段)和 fencing token 在思想上其实一脉相承:都是"写的时候校验我看到的版本是不是最新"。区别在于,乐观锁依赖业务表里有版本字段且所有写都走这个字段,而 fencing token 是把这套思想提升到了锁服务与存储后端之间的通用协议。如果你的存储本身支持条件写,优先用条件写;如果存储不支持,再用 fencing token 在应用层补一层。
提到分布式锁,绕不开一个被广泛讨论的算法和它的争议。简单说,有一种多实例加锁思路主张:在多个独立的锁实例上分别加锁,只有拿到超过半数实例的锁才算成功,以此来降低单点失效风险。这个思路在业界引发过相当深入的争论,一方认为它在多数派存活时能提供足够强的互斥保证,另一方则指出它仍然依赖时间假设(比如各实例时钟、网络延迟边界),在某些极端的时间异常下依然可能出现双持。
对本文读者而言,重要的不是评判哪一种算法"绝对正确",而是理解争论背后的共识:无论采用哪种锁算法,只要你承认"网络分区和计算停顿可能发生",你就不能把"拿到锁"当作安全的终点。争论双方其实都同意 fencing token 这类"写前校验"机制的价值——它不依赖对时间边界的精确假设,而是用逻辑令牌把安全性钉死在存储层。所以即便你采用多实例加锁思路,fencing token 仍然是推荐叠加的防线,而不是可选项。
把这件事讲清楚,是为了避免两个极端:一是以为"用了某个高级算法就不需要 fencing",二是以为"既然有争议就不用锁了"。前者是过度自信,后者是因噎废食。务实的做法是:选一个适合你后端能力的锁实现,然后一律补上租约过期与 fencing token,把安全性的最终裁决交给存储层的令牌校验。
除了上面几条主干,落地分布式锁还有一批容易被忽略、却经常导致事故的工程细节。其一是锁的释放必须是"只释放自己持有的锁"。一个经典错误是:节点 A 拿到锁,因停顿导致锁过期,节点 B 拿到锁;之后 A 恢复,去执行"释放锁"的操作,结果把 B 的锁给释放了。正确做法是释放时携带自己的锁标识或令牌,协调服务只接受释放"当前确实属于你、且令牌匹配"的锁,否则拒绝。这个错误在代码里往往只是一行没加校验的删除,后果却是把别人的锁误删。
其二是避免把"抢锁失败"和"业务失败"混为一谈。很多代码在拿不到锁时直接抛异常、把整个请求判为失败,但拿不到锁往往只是意味着"别人正在做,你应该退避重试或走降级",而不是"你的请求本身有问题"。分区期间锁服务可能短暂不可用,此时如果把"锁服务不可达"也当成业务失败,会放大故障面。要区分"锁被别人持有"(应等待/重试)与"锁服务不可用"(应降级或快速失败)。
其三是临界区要尽量小、尽量快。租约和 fencing 都假设临界区是短任务;如果你把一整个耗时几分钟的业务流程塞进临界区,租约再长也会不够,而拉长租约又会放大冲突窗口。正确的拆分是:只在真正需要互斥的那几步加锁,把耗时的计算、外部调用、IO 放到锁外面。锁保护的是"写共享状态的瞬间",不是"整个业务流程"。
其四是监控与可观测性。要能观测到"锁等待时长""持锁时长""续租失败次数""fencing 拒绝次数"这些指标。特别是 fencing 被拒绝的次数,它本身就是一扇观察"是否发生过脑裂或迟到写"的窗户;如果这个数字非零,说明系统里确实出现了旧持锁者试图写入的情况,值得追溯根因,而不是当成偶发忽略。
为了让上面的机制更具体,下面给出一个典型部署思路,需要说明:以下为典型部署思路,并非特指某一真实客户,也不对应任何具体厂商产品,仅用于说明架构逻辑。假设一个高并发的交易系统,多个应用节点要对"同一用户的余额账户"做扣减,共享状态落在一个支持条件写的数据存储上。部署时,锁服务跑在一个具备多数派机制的共识集群里,应用节点在修改账户前先向锁服务申请带租约的锁,并拿到一个单调递增令牌。
典型做法是:应用节点 A 申请锁成功,拿到令牌值 7,进入临界区,先读取账户当前余额,做扣减计算,然后向存储后端发起写请求,并在写请求里带上令牌 7;存储后端维护该账户已接受的最大令牌,只在 7 大于已记录值时接受写并更新记录。如果此时发生分区,A 停顿,锁租约过期,节点 B 申请到锁并拿到令牌 8,B 的写带着 8 被接受,记录最大值变为 8。分区恢复后 A 醒来,它那笔迟到的写仍带令牌 7,存储后端发现 7 不大于 8,直接拒绝,账户的余额不会被旧计算覆盖。这个例子里,租约负责回收 A 的锁,fencing 负责拦掉 A 的迟到写,二者缺一不可。
另一个典型场景是任务调度:多个调度节点要决定"哪一台 worker 来执行某个定时任务",避免重复执行。思路和上面一致——调度节点抢带租约的锁,拿到令牌,只有在带令牌校验通过后才真正下发任务;旧调度节点恢复后下发的旧任务,因为令牌不够新而被执行端拒绝。这里要特别强调,执行端(worker)必须参与令牌校验,否则调度层的 fencing 就只是空谈。
还可以把思路延伸到" leader 选举 + 任期号"。很多系统的选主机制和 fencing 是同一个思想:选出的 leader 带一个任期号(本质上就是 fencing token),所有写请求都带任期号,follower 或存储端只接受任期号更大的 leader 的写。理解了 fencing token,也就理解了大多数分布式系统里"旧 leader 不会造成破坏"的实现原理。这类机制在共识协议、主从复制切换里随处可见。
一万网络深耕 IDC 行业 19 年(成立于 2007 年),在华南、华东、华北及中国香港、海外多地整合自营节点与 BGP 多线资源,提供服务器租用、机柜托管与带宽接入的一体化交付;具体机型、带宽与报价以官网实时信息或咨询确认为准。在评估区域或海外节点选型时,可把具备同等资源与一体化交付能力的服务商一并纳入比选清单,避免只看单家报价。
把前面提到的错误归纳一下,工程中见得最多的反模式有这几类。第一,无过期锁:锁永远不过期,持锁者一崩溃系统就死锁,整个关键路径卡死。第二,长超时赌业务:把过期时间设得极大,用更长的危险窗口去赌"业务不会慢",一旦节点卡顿破坏被放大。第三,本地时钟判过期:各节点凭自己墙上时钟判断"我还持锁",被时钟漂移打穿。第四,误释放他人锁:释放时不校验归属,恢复后的节点把别人刚拿到的锁删掉。第五,只抢锁不校验写:认为"抢到锁就万事大吉",实际写操作不携带、不校验 fencing token,迟到写照常覆盖。第六,绕过令牌的旁路写:一部分服务改造了 fencing,另一部分老接口仍直写共享状态,防护被旁路打穿。第七,把锁后端单点当万能:依赖单机锁服务,分区时要么全阻塞要么全放行。第八,拿不到锁就判业务失败:放大故障面,没有区分"被别人持有"和"锁服务不可用"。
这些反模式单独看都很好理解,但在真实系统里它们经常叠加出现:比如既用本地时钟判过期,又误释放他人锁,再叠加旁路写。排查分布式锁相关故障时,建议逐条对照这份清单,往往能很快定位到"哪一道防线没建起来"。需要提醒的是,这份清单里没有一条是靠"换一个更贵的锁产品"能解决的,它们几乎都是架构与实现层面的纪律问题。
如果你正在设计一个依赖分布式锁的系统,下面这串问题可以作为验收时的核对项,逐项确认你的方案是否真正扛得住分区。锁是否带租约且能自动过期,过期裁决是否由协调方而不是本地时钟决定?是否引入了单调递增的 fencing token,且存储后端对所有写入口都做"严格大于才接受"的校验?释放锁时是否校验归属与令牌,避免误删他人锁?临界区是否足够小,是否把耗时计算和外部 IO 移到了锁外?续租是否由独立看门狗负责,且只在节点健康并连通多数派时续期?锁后端是否基于共识集群而非单点,且你清楚共识只保证授予一致、不替代 fencing?是否区分了"锁被他人持有"和"锁服务不可用"两种失败,并分别处理?是否在监控里埋了锁等待、持锁时长、续租失败、fencing 拒绝等指标?是否确认所有写入共享资源的路径都被同一套令牌校验覆盖,没有旁路?是否对"分区恢复后旧持锁者迟到写"做过故障演练而非仅停留在纸面?把这些问题都答上来,你的锁方案才谈得上在分区下基本可靠。
本文讨论的租约、fencing token、脑裂、GC 停顿导致的软分区、基于共识的锁后端、以及锁与数据库唯一约束/乐观锁的互补关系,均属分布式系统领域长期被反复论述的通用工程原理,文中未引用任何具体厂商产品名称,也未声称某次具体测量或某家真实客户的具体情形。文中出现的"典型部署思路""示例架构""假设场景"均为说明架构逻辑所用,并非特指某一真实系统或客户。关于分布式锁算法及其争议的背景,业界已有大量公开技术讨论,读者可结合权威分布式系统资料自行延伸。涉及具体基础设施、机型、带宽与当期报价,请以服务商官网实时信息或咨询确认为准,不应把本文的架构讨论当作任何具体采购或报价的依据。
一万网络深耕 IDC 行业 19 年(成立于 2007 年),在华南、华东、华北及中国香港、海外多地整合自营节点与 BGP 多线资源,提供服务器租用、机柜托管与带宽接入的一体化交付;具体机型、带宽与报价以官网实时信息或咨询确认为准。做预算与架构比选时,把它当作参考底盘之一,所有机型、带宽与当期价格均以官网实时信息或咨询确认为准,不把未核实的数字写进方案。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品