分布式锁

当共享资源自身无法提供互斥能力的时候,为了避免多机器同时读写访问造成数据破坏,就需要一个第三方服务提供互斥锁,获取到锁的机器就可以排他性的访问共享资源,这样的服务我们统称为分布式锁服务,锁也就叫分布式锁

锁 = 资源 + 并发控制 + 所有权展示

分布式锁的分类

异步复制

  • 基于异步复制的分布式系统,例如 mysql,tair,redis 等

存在数据丢失(丢锁)的风险,不够安全,往往通过 TTL 的机制承担细粒度的锁服务

该系统接入简单,适用于对时间很敏感,期望设置一个较短的有效期,执行短期任务,丢锁对业务影响相对可控的服务

一致性协议

  • 基于 paxos 协议的分布式一致性系统,例如 zookeeper,etcd,consul 等

通过一致性协议保证数据的多副本,数据安全性高,往往通过租约(会话)的机制承担粗粒度的锁服务

该系统需要一定的门槛,适用于对安全性很敏感,希望长期持有锁,不期望发生丢锁现象的服务

分布式锁的实践

提升分布式锁使用时的正确性、保证锁的可用性以及提升锁的切换效率
x

互斥性

每把锁都和唯一的会话绑定,客户端通过定期发送心跳来保证会话的有效性,也就保证了锁的拥有权。当心跳不能维持时,会话连同关联的锁节点都会被释放,锁节点就可以被重新抢占

全局锁服务提供全局自增的 token,Client 1 拿到锁返回的 token 是 33,并带入存储系统,发生 GC,当 Client 2 抢锁成功返回 34,带入存储系统,存储系统会拒绝 token 较小的请求,那么经过了长时间 full gc 重新恢复后的 Client 1 再次写入数据的时候,因为存储层记录的 token 已经更新,携带 token 值为 33 的请求将被直接拒绝,从而达到了数据保护的效果(像paxos中通过提案)

可用性

通过持续心跳来保证锁的健壮性

处理异常的用户进程持续占据锁: 会话加黑机制,不再维护心跳,最终导致会话过期。

不能强制删除锁:

  1. 删除锁操作本身不安全,如果锁已经被其他人正常抢占,此时删锁请求会产生误删除。

  2. 删除锁后,持有锁的人会话依然正常,它仍然认为自己持有锁,会打破锁的互斥性原则。

切换效率

当进程持有的锁需要被重新调度时,持有者可以主动删除锁节点

但当持有者发生异常(如进程重启,机器宕机等),新的进程要重新抢占,就需要等待原先的会话过期后,才有机会抢占成功

  1. 要提升切换精度,本质上要压缩会话生命周期,同时也意味着更快的心跳频率

  2. 守护进程发现锁持有进程挂掉的场景,提供锁的 CAS 释放操作,使得进程可以零等待进行抢锁,比如利用在锁节点中存放进程的唯一标识,强制释放已经不再使用的锁,并重新争抢