分布式锁
CAP理论:在一个分布式系统中,做多满足下面三项中的两项
C
一致性: 在分布式系统中所有的数据备份,在同一时刻都有相同的值A
可用性: 保证每个请求不管成功还是失败都有响应P
分区容错性:任何信息的丢失和失败都不影响系统的运行
02 分布式锁
0201 概述
介绍
在分布式系统中访问共享资源时需要采取一致互斥机制,来防止相互干扰,以保证一致性
分布式锁:在分布式模型中,保证数据只有一份(限制),锁技术
分布式锁应该具备的条件
互斥性: 在分布式系统中,一个方法在同一时间 只能被一个机器的一个线程执行
高可用的获取锁与释放锁
高性能的获取锁与释放锁
可重入性:具备可重入性,具备锁失效机制,防止死锁,,即就算一个客户端持有锁,因系统失败未主动释放锁,也需要保证后续其他用户能够加锁成功
非阻塞:没有获取到锁直接返回获取锁失败
应用场景:秒杀与抢优惠卷
0202 分布式锁的几种实现方式
基于数据库、基于redis,基于zookeeper
020201 基于数据库
A. 悲观锁
利用
select … where xx=yy for update排他锁,不建议使用
B. 乐观锁
在表中添加一个时间戳或者是版本号的字段来实现
版本号不一致,更新失败
020202 zookeeper分布式锁
利用zookeeper的临时有序节点,顺序号最小的获取锁
实现步骤:
创建一个mylock目录
线程a在mylock目录下创建临时有序节点
获取mylock目录下所有的子节点,然后获取比自己小的节点,如果不存在,则说明当前线程的顺序号最小,获取锁
线程b创建节点向该节点注册监听事件,监听该节点,其他节点依次监听自己的上一个节点
线程a处理完后,删除自己的节点,其他节点监听变更事件后,重新去获取锁
使用Apache的开源库Curator,它是一个ZooKeeper客户端,Curator提供的InterProcessMutex是分布式锁的实现,acquire方法用于获取锁,release方法用于释放锁
使用案例
InterProcessMutex interProcessMutex = new InterProcessMutex(client,"/anyLock");
interProcessMutex.acquire();
//业务逻辑
interProcessMutex.release();
优缺点:
可靠性高
性能较好
CAP模型中属于CP
020203 redis分布式锁
主要基于命令:SETNX key value
redis分布式锁:在分布式系统中采取一致互斥机制,
考虑因素:
原子性:lua脚本
synchronized只能解决单进程的原子性问题
Redis2.6.12之前的版本,只能通过lua脚本来保证原子性
Redis 2.6.12版本及以上推荐使用set原生命令
死锁,删除锁失败
异常导致删除锁失败,解决方案: finally里删除锁
系统奔溃不执行删除锁逻辑,解决方案: 设置锁过期时间,考虑原子性,和时长合理性
错误的释放锁
流程:
A进程加锁并设置超时时间,比如10秒
当10秒后进程A的锁已经被redis中释放了
B进程请求进来,加锁成功
A进程执行完毕,就把B进程的锁释放了,
接着C进程进来,加锁成功,等等......
以此类推
解决方案:
加锁时将值设为唯一值,比如uuid,
Redisson
使用如下:
a.引入依赖
<dependency>
<groupId>org.redissongroupId>
<artifactId>redisson-spring-boot-starterartifactId>
<version>3.13.4version>
dependency>
b.增加配置文件
c.分布式锁的实现
03 总结:
-
追求数据可靠性/强一致性:使用Zookeeper
-
追求性能:选择Redis,推荐Redisson
-
Redis分布式锁目前最大问题在于:主从模式下/集群模式下,master节点宕机,异步同步数据导致锁丢失问题
-
Redis的RedLock算法具有很大争议性,一般不推荐使用
参考原文地址: 【分布式锁】三种分布式锁的实现https://blog.csdn.net/jiandanokok/article/details/114296755?