1小时掌握Redisson实现Redis分布式锁以及Redlock分布式锁

愿天堂没有BUG

共 1963字,需浏览 4分钟

 · 2021-09-26

利用中秋节时间补一下redis分布式锁的知识,在B站上看到程序员诸葛老师讲的《Redisson实现Redis分布式锁以及Redlock分布式锁》课程感觉不错。

超卖问题,应该是97 但是三个线程执行完之后依旧是99

问题:公司一般两台机器或者多台机器,多点

模拟场景

Jmeter使用  springBoot启动两个机器,改一下端口

并发量越高,出现“超卖”的机率越大。在分布式环境下,产生的锁是锁不住的,不同的请求发到nginx上,帮忙做负载均衡,如果两个请求均匀地分发到不同的Tomcat去,生出来的锁只在JVM进程内有效, 在同一个Tomcat内有效,没办法跨tomcat控制的。

入门级分布式锁的实现

注:redis单线程

抛异常导致请求死锁

宕机

宕机,redis锁还存在,其他机器请求时候

原子执行,不可分割,

请求执行时间很长,

  • 假设请求时间比较长,执行15s,假设请求质控relStock时,过去了10s,这把锁被redis 清理掉了,

意味这什么呢?高并发场景,外面不断有请求过来访问接口

  • 第2个请求就可以加锁成功,因为第一个请求的锁被redis清除掉了,假设新来的请求执行时间为8s

  • 第1个请求此时执行了10s,再执行5s,删除之前的key,会删除第二个线程的key,删锁操作

  • 超高并发过程中,之前加的锁可能永久失效,只要高并发存在,锁会永久失效,问题会被放大,秒杀场景,商家会亏死

问题本质

自己加的锁,被其他线程删除

开源框架解决

redis源码分析

/**
* 获取分布式锁
*
* @param lockKey 锁定
* @param waitTime 锁定等待时间
* @param leaseTime 获取到的锁的存活时间,到期后自动释放
* @return 未能锁定则返回null
*/
@Override
public RLock tryLock(String lockKey, long waitTime, long leaseTime) {
RLock lock = redisson.getLock(lockKey);
try {
if (lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS)) {
return lock;
}
} catch (InterruptedException ignore) {
if (log.isWarnEnabled()) {
log.warn("Redisson tryLock exception", ignore);
}
}
return null;
}
复制代码

public RLock getLock(String name) {
return new RedissonLock(this.connectionManager.getCommandExecutor(), name);
}
复制代码

lua具有原子性,当做一条命令执行

从cap角度剖析redis&zookeeper锁架构

redis很少单机版,至少主从 哨兵 集群 如果redis是多节点情况下,会不会出现什么问题?若redis是主从、哨兵模式还是会有问题的。

加锁之后,redis底层设置key,redis默认情况下是异步同步,主节点写之后,异步同步从节点,主要如果主节点key写成功之后,马上返回客户端,锁加成功了,redis主节点开始同步从节点,假设刚开始同步从节点,主节点挂掉了怎么办?

CAP原则:redis集群满足AP架构

zk满足CP架构(ZAB协议):加锁向主节点写,不会立刻向客户端返回加锁成功的结果,而是先向从节点同步,同步成功之后,才告诉客户端加锁成功了,有延迟,牺牲了一点可用性,达到一致性。即使集群挂掉,对外也是不可用,也要达到数据一致性。

万一主节点挂掉,从从节点选举出新的主节点

对并发要求比较高,建议选择redis,即使出现redis主从架构失效问题,出现概率不大,可以人工补偿措施,写脚本补偿。

Redlock 不推荐使用,使用zk

需要很多机器加锁成功,才能算成功,性能会受影响,也存在锁回滚情况。


作者:程序员说书
链接:https://juejin.cn/post/7009958172265824293
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报