Redis篇之分布式锁知识点总结---(温故而知新版本)---(加油哦)
Posted 奔赴在自己的热爱中
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis篇之分布式锁知识点总结---(温故而知新版本)---(加油哦)相关的知识,希望对你有一定的参考价值。
分布式锁:
分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用本地锁就没办法实现资源的互斥访问了。于是,分布式锁 就诞生了。
一个最基本的分布式锁需要满足:
互斥 :任意一个时刻,锁只能被一个线程持有;
高可用 :锁服务是高可用的。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。
可重入:一个节点获取了锁之后,还可以再次获取锁。
基于 Redis 实现分布式锁
在 Redis 中, SETNX 命令是可以帮助我们实现互斥。SETNX 即 SET if Not eXists (对应 Java 中的 setIfAbsent() 方法),如果 key 不存在的话,才会设置 key 的值。如果 key 已经存在, SETNX 啥也不做。
为了防止误删到其他的锁,我们使用 Lua 脚本通过 key 对应的 value(唯一值)来判断。
选用 Lua 脚本是为了保证解锁操作的原子性。因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,从而保证了锁释放操作的原子性
// 释放锁时,先比较锁对应的 value 值是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
为了避免锁无法被释放,给这个 key(也就是锁) 设置一个过期时间 。
一定要保证设置指定 key 的值和过期时间是一个原子操作
如果操作共享资源的时间大于过期时间,就会出现锁提前过期的问题,进而导致分布式锁直接失效;如果锁的超时时间设置过长,又会影响到性能;
如何解决?
实现锁的优雅续期?
Redisson实现
Redisson 中的分布式锁自带自动续期机制,其提供了一个专门用来监控和续期锁的 Watch Dog( 看门狗),如果操作共享资源的线程还未执行完成的话,Watch Dog 会不断地延长锁的过期时间,进而保证锁不会因为超时而被释放。
renewExpiration() 方法包含了看门狗的主要逻辑:
private void renewExpiration()
//......
Timeout task = commandExecutor.getConnectionManager().newTimeout(new TimerTask()
@Override
public void run(Timeout timeout) throws Exception
//......
// 异步续期,基于 Lua 脚本
CompletionStage<Boolean> future = renewExpirationAsync(threadId);
future.whenComplete((res, e) ->
if (e != null)
// 无法续期
log.error("Can't update lock " + getRawName() + " expiration", e);
EXPIRATION_RENEWAL_MAP.remove(getEntryName());
return;
if (res)
// 递归调用实现续期
renewExpiration();
else
// 取消续期
cancelExpirationRenewal(null);
);
// 延迟 internalLockLeaseTime/3(默认 10s,也就是 30/3) 再调用
, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);
ee.setTimeout(task);
Watch Dog 通过调用 renewExpirationAsync() 方法实现锁的异步续期,renewExpirationAsync 方法调用 Lua 脚本实现的续期,这样做主要是为了保证续期操作的原子性
如何使用 Redisson 实现分布式锁:
// 1.获取指定的分布式锁对象
RLock lock = redisson.getLock("lock");
// 2.拿锁且不设置锁超时时间,具备 Watch Dog 自动续期机制
lock.lock();
// 3.执行业务
...
// 4.释放锁
lock.unlock();
只有未指定锁超时时间,才会使用到 Watch Dog 自动续期机制:
// 手动给锁设置过期时间,不具备 Watch Dog 自动续期机制
lock.lock(10, TimeUnit.SECONDS);
可重入锁?
可重入锁指的是在一个线程中可以多次获取同一把锁,比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法 ,而无需重新获得锁
如何实现可重入锁?
实现核心思路是线程:在获取锁的时候判断是否为自己的锁,如果是的话,就不用再重新获取了。为此,我们可以为每个锁关联一个可重入计数器和一个占有它的线程。当可重入计数器大于 0 时,则锁被占有,需要判断占有该锁的线程和请求获取锁的线程是否为同一个。
温故知新分布式事务及分布式锁系列文章总结石杉的架构笔记
周一至五早8点半!精品技术文章准时送上!
“ 这周我们来小结一下分布式系列的文章,包含分布式事务及分布式锁,无论是工作还是面试,都是非常重要的一块知识点。
一
通过一个真实的电商业务场景驱动,我们介绍了什么是TCC分布式事务、如何落地实现其三个阶段,同时,给予了读者朋友一些思考问题,这都是真实生产项目中使用TCC分布式事务必须考虑到的因素。
如果还有不太清楚的小伙伴,赶紧点击下面链接,温习一遍吧!
点击下方文字直接跳转↓↓↓
二
实际生产中,各个服务间的调用很可能是异步的,所以我们这篇文章,聊了聊基于MQ的异步调用如何保证各个服务间的分布式事务!详细阐述了用来实现分布式事务的可靠消息最终一致性方案的核心流程。
然后更进一步,深入剖析并指出了保障可靠消息最终一致性方案高可用的关键因素。
最后通过一个真实的案例,给出了实际的保障99.99%高可用的解决方案,并且指出了其中可能存在的一些大坑。
点击下方文字直接跳转↓↓↓
三
接下来进入另一个热门技术点:分布式锁,首先这篇文章,我们基于优秀的Redisson框架,深入剖析了Redis分布式锁的底层原理。
我们讨论了加锁 / 释放锁机制、锁互斥机制、watch dog自动延期机制、可重入加锁机制。
并且更进一步,分析了此种方案下Redis分布式锁的缺陷,希望能帮助到各位同学,在实际项目中绕过雷区!
点击下方文字直接跳转↓↓↓
四
通过一道真实的面试题引入:每秒上千订单场景下,如何对分布式锁的并发能力进行优化?还有不清楚的同学,赶紧复习一遍吧!
点击下方文字直接跳转↓↓↓
五
之前结合Redisson框架,给大家聊了聊Redis分布式锁背后的原理。这篇文章,同样基于常用的Curator开源框架,来给大家聊一聊Zookeeper分布式锁的实现原理。
还记得多客户端获取和释放zookeeper分布式锁的整个流程和背后的原理吗?忘了的同学,抽个10分钟时间,赶紧的复习一波吧!
点击下方文字直接跳转↓↓↓
END
并发系列文章,正在更新中,欢迎关注:
《大白话聊聊Java并发面试问题之volatile到底是什么?》
《大白话聊聊Java并发面试问题之Java 8如何优化CAS性能?》
《大白话聊聊Java并发面试问题之公平锁与非公平锁是啥?》
《大白话聊聊Java并发面试问题之微服务注册中心的读写锁优化?》,敬请期待
推荐阅读:
如有收获,请帮忙转发,您的鼓励是作者最大的动力,谢谢!
一大波微服务、分布式、高并发、高可用的原创系列文章正在路上,欢迎扫描下方二维码,持续关注:
石杉的架构笔记(id:shishan100)
十余年BAT架构经验倾囊相授
以上是关于Redis篇之分布式锁知识点总结---(温故而知新版本)---(加油哦)的主要内容,如果未能解决你的问题,请参考以下文章