会话什么时候算过期?过期之后客户端看到什么?这篇用「暂停服务端」「冻结客户端」两种方式,把会话超时前后的状态变化按毫秒记下来,这也是理解 GC 停顿、网络抖动为什么会让锁「丢掉」的基础。
状态变化: [] 同一个会话: True | 临时节点还在: True
状态变化: [(3479, 'SUSPENDED'), (9007, 'LOST'), (9140, 'CONNECTED')] 原会话 id 0x1000bc872a30002 → 现在 0x1000bc872a30003;临时节点 /eph2 还在: False
这里服务端本身被暂停,所以「会话过期」是服务端恢复之后才判定并通知的;如果是真正的网络分区(服务端一直在运行),服务端会在超时到期时就删除临时节点,客户端要等到重新连上才知道。
客户端进程冻结前 /eph3 存在: True 冻结客户端后 /eph3 在 6208 ms 后被服务端删除(会话超时 6000 ms)
这就是 GC 长停顿会让分布式锁失效的原因:客户端停顿超过会话超时,服务端已经删掉了它的锁节点,它恢复后还以为自己持有锁。解决办法是客户端在 SUSPENDED / LOST 时停止依赖锁的操作(第 79 篇),本文只验证了现象。