首页 > 其他 > 详细

分布式锁方案

时间:2021-05-11 22:10:44      阅读:32      评论:0      收藏:0      [点我收藏+]

数据库实现分布式锁

  • 基于主键或唯一索引来实现,想要获得锁,就插入一条记录。
  • 并发下只有一个插入可以成功(获得锁),插入失败就获得锁失败,释放锁时就删除这条记录。
  • 失败的线程轮询再次操作,直至获得锁成功

缺点:

  • 锁没有失效时间,如果获得锁成功后未释放锁(服务挂了),其他线程无法获取锁。
  • 大量的轮询会消耗CPU
  • 单机的 mysql 无法满足高可用
  • 集群高可用场景下,主机宕机主备切换存在数据一致性问题(数据同步本身是弱一致性有延迟,备库可能缺失一部分数据)

Redis实现分布式锁

  • 类似数据库,set命令获得锁(set + expire 不行,不是原子的),del命令释放锁
  • 获得锁失败的线程轮询再次请求。
  • 获得锁的服务宕机了怎么办?设置过期时间防止死锁
  • 锁到期被删除怎么办?加一个守护线程,在快要过期时给锁续约
  • 锁被误删怎么办?set 时 value 设置成唯一值,del 时比较 value;也就是说我只能释放我自己加的锁。

缺点:

  • 大量的轮询会消耗CPU
  • 单机的 redis 无法满足高可用
  • 集群高可用场景同 mysql

Zookeeper实现分布式锁

能够解决上述方案的所有痛点:

  • 服务宕机引发死锁?我们使用临时节点,一定时间内接收不到服务的心跳包,临时节点自动删除。
  • 线程主动轮询?有延迟,有压力,使用 watch 机制
  • watch 同一个节点,删除事件唤醒大量线程争抢锁?有压力。只 watch 上一个节点。
  • 单机问题?支持分布式高可用
  • 主备切换存在一致性问题?选举选出的节点肯定是数据最全的。即使有数据缺失,其内部队列中的log是能够保证最终一致性的。而且其顺序一致性保证了后来的请求无法影响到先到的请求。

过程是这样的:

  1. 线程在目录下创建一个临时序列节点
  2. 线程获取目录下的所有节点,如果它刚才创建的节点是最小节点,认为这个线程获得了锁;如果不是最小节点,这个线程 wait,同时监听比自己小的节点的删除事件(exist方法)
  3. 无论是线程结束删除节点(释放锁),还是超时删除节点,都会唤醒监听其节点删除事件的线程,被唤醒的线程获得锁。

分布式锁方案

原文:https://www.cnblogs.com/felix-1/p/14756616.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!