当共享资源自身无法提供互斥能力的时候,为了避免多机器同时读写访问造成数据破坏,就需要一个第三方服务提供互斥锁,获取到锁的机器就可以排他性的访问共享资源,这样的服务我们统称为分布式锁服务,锁也就叫分布式锁
锁 = 资源 + 并发控制 + 所有权展示
分布式锁的分类
异步复制
- 基于异步复制的分布式系统,例如 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中通过提案)
可用性
通过持续心跳来保证锁的健壮性
处理异常的用户进程持续占据锁: 会话加黑机制,不再维护心跳,最终导致会话过期。
不能强制删除锁:
删除锁操作本身不安全,如果锁已经被其他人正常抢占,此时删锁请求会产生误删除。
删除锁后,持有锁的人会话依然正常,它仍然认为自己持有锁,会打破锁的互斥性原则。
切换效率
当进程持有的锁需要被重新调度时,持有者可以主动删除锁节点
但当持有者发生异常(如进程重启,机器宕机等),新的进程要重新抢占,就需要等待原先的会话过期后,才有机会抢占成功
要提升切换精度,本质上要压缩会话生命周期,同时也意味着更快的心跳频率
守护进程发现锁持有进程挂掉的场景,提供锁的 CAS 释放操作,使得进程可以零等待进行抢锁,比如利用在锁节点中存放进程的唯一标识,强制释放已经不再使用的锁,并重新争抢