为什么使用?
我们在分布式架构下,高并发下的情况下,对共享资源进行一个操作,会出现一个资源不一致的情况。这种问题,我们就需要使用到分布式锁。
怎么使用?
实现分布式锁主要有三种方案:
1.数据库的排他锁
我们设置一个字段作为唯一比如设置成lock当有请求来的时候,就修改成1,就相当于加锁,然后当多个请求到数据库的时候,这时候也只能保证只有修改成1的那个线程进行操作,其他线程则不能。然后当修改完成之后在将这个字段设置成0,代表解锁。其他线程就可以进行操作。
缺点:太依赖数据库,如果当前线程在解锁的时候,解锁没成功,会让当前资源一直被锁在 数据库。
2.redis的redisson
解释无锁:
当第一个线程获取锁,加上了锁,设置了10s时间,这时候开始处理业务,然后12s还没处理完成,这把锁已经过期,这时候第二 个线程发现没有锁了,就上锁,然后第一个线程执行完业务,去释放锁,他不清楚这把锁是否是自己的,然后就释放了,这时候就成了无锁状态。设置锁的时候,设置value的唯一性,所以去删除的时候通过value(唯一性)判断是否是自己的锁,是才释放。
死锁:
没有设置过期时间,会产生死锁,所以需要设置过期时间,但是设置时间也会产生问题,必须保证原子性
加锁的原子问题:
redis4.0之前只能通过lua脚本来保证原子性,在4.0之后可以通过一条命令直接带上过期 时间,这个命令本身就是原子性。
解锁也有原子的问题:
在判断的时候,是自己的锁,但是要删除的那一瞬间,锁过期了,锁还没有删除,然后其他线程有开始加锁,然后第一个线程又删除了别人的锁。
续期的问题
redisson有一个看门狗机制,他设置默认时间30s,当20s的时候判断是否还有锁,有就继续将时间设置到30s。
主从架构锁失效?
但是这个还是有一些问题,比如redis的主从复制,当主结点加上了锁,准备同步到从节点上去,然后宕机了,这时候,从节点没有加上锁。还是会出现问题。
解决:redlock或者用zookeeper
其实redisson底层大部分保证原子性的都是通过lua脚本来实现的
3.zookeeper
zookeeper的结点相当于文件的目录,保证唯一且还能存储数据,以树状的方式来存储结点信息。他因为name是唯一的,所以当我在创建znode结点的时候,就会创建失败。
zookeeper里面的结点有,持久化结点和临时结点,他们都可以有有序性。
所以当里面某一个结点宕机了,这时候也不用担心死锁的状态,因为他临时结点特性,宕机后会在一定时间后进行一个删除,这里涉及到zookeeper的一个watch机制。
它里面有一个羊群效应,意思是当某个结点过期,这时候假设上百个客户端来争抢。就会产生这个羊群效应,但是因为zookeeper里面的结点是一个有序的,他是通过从一个结点往下一直扩展,假设当前的一个结点是znode001,那么下个结点会跟这个顺序一直传递下去,所以每次我们获取的时候,就最小的获取,我下个结点想要获取,就只能判断我前一个结点是否释放了锁,释放了才能去获取,不然就一直等待。
三种实现分布式锁
最新推荐文章于 2023-06-27 10:27:50 发布