分布式锁

为什么需要分布式锁

应用中需要避免多个线程在同一时间对同一个共享变量做修改
在单机部署的项目中,为了避免上述现象,需要对变量或代码块做同步
在分布式部署的项目中,为了避免上述现象,用同步是解决不了的(因为相同的项目部署在了多台服务器,同步只能解决单台服务器的问题),
所以就需要分布式锁,保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行

分布式锁有几种实现方式

主流的实现方式有三种
1、利用数据库实现
2、利用缓存(redis)实现
3、利用zookeeper实现

简述各种方式及优缺点

1、利用数据库实现

优点:简单、易理解
缺点:高并发时,性能差,增加了数据库开销

方法一:

  • 新建一张表,向该表中添加相同主键的一条记录, 哪个线程添加成功,即获得了分布式锁,
  • 然后执行相关逻辑,逻辑执行完之后,删除数据库表中的该数据,删除即代表解锁

方法二、

  • 使用for update,数据表会在查询的时候添加排它锁,
  • 多个线程同时来执行时,只有一个会成功加锁,其余的线程都会阻塞,
  • 加锁成功的线程即获得分布式锁的线程,该线程执行相关逻辑,
  • 逻辑执行完之后,使用connection.commit解锁,此时阻塞的其他线程中会有一个加锁成功….

2、使用redis缓存实现

优点:效率高
缺点:设置过期时间过长过短都不合适,需要根据实际情况权衡

大概思路:

  • 向redis中添加key,并设置过期时间
  • 如果key已存在,则添加失败
  • 如果key不存在,则添加成功
  • 添加成功,即获得了分布式锁
  • 获得锁的线程执行业务逻辑,执行完之后,删除redis中的key(即解锁)

3、通过zookeeper实现

优点:有效的解决单点问题,不可重入问题,非阻塞问题以及锁无法释放的问题。实现起来较为简单
缺点:因为每次在创建锁和释放锁的过程中,都要动态创建、销毁临时节点来实现锁功能。
ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同步到所有的 Follower 机器上。

大概思路:

  • 每一个锁都是zookeeper上的一个znode(普通节点)
  • 当多个线程来获取锁时,都会在该znode上创建有序临时子节点,每个有序临时子节点都有自己的序号
  • 只有序号最小的可以拥有锁,然后执行相关逻辑,执行完成之后删除子节点(即解锁),触发监听
  • 序号如果不是最小的,则没有获得锁,设置监听事件,监听序号比本身小的前一个节点,
  • 等待事件触发再次比较是否是最小的

版权声明:本文为jis121原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/jis121/p/10899388.html