有关Redisson做为实现分布式锁,总的分3大模块来说。java
一、Redisson实现分布式锁原理 二、Redisson实现分布式锁的源码解析 三、Redisson实现分布式锁的项目代码(能够用于实际项目中)
本文只介绍Redisson如何实现分布式锁的原理。其它的会在接下来的博客讲,最后有关Redisson实现分布式锁的项目代码
的博客中会放上项目源码到GitHub上。redis
当咱们在设计分布式锁的时候,咱们应该考虑分布式锁至少要知足的一些条件,同时考虑如何高效的设计分布式锁,这里我认为如下几点是必需要考虑的。数据库
在分布式高并发的条件下,咱们最须要保证,同一时刻只能有一个线程得到锁,这是最基本的一点。服务器
在分布式高并发的条件下,好比有个线程得到锁的同时,尚未来得及去释放锁,就由于系统故障或者其它缘由使它没法执行释放锁的命令,致使其它线程都没法得到锁,形成死锁。并发
因此分布式很是有必要设置锁的有效时间
,确保系统出现故障后,在必定时间内可以主动去释放锁,避免形成死锁的状况。异步
对于访问量大的共享资源,须要考虑减小锁等待的时间,避免致使大量线程阻塞。分布式
因此在锁的设计时,须要考虑两点。高并发
一、锁的颗粒度要尽可能小
。好比你要经过锁来减库存,那这个锁的名称你能够设置成是商品的ID,而不是任取名称。这样这个锁只对当前商品有效,锁的颗粒度小。性能
二、锁的范围尽可能要小
。好比只要锁2行代码就能够解决问题的,那就不要去锁10行代码了。ui
咱们知道ReentrantLock是可重入锁,那它的特色就是:同一个线程能够重复拿到同一个资源的锁。重入锁很是有利于资源的高效利用。关于这点以后会作演示。
针对以上Redisson都能很好的知足,下面就来分析下它。
为了更好的理解分布式锁的原理,我这边本身画张图经过这张图来分析。
线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。
线程去获取锁,获取失败: 一直经过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis数据库。
这个比较难理解,找了些许资料感受也并无解释的很清楚。这里我本身的理解就是:
在一个分布式环境下,假如一个线程得到锁后,忽然服务器宕机了,那么这个时候在必定时间后这个锁会自动释放,你也能够设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生。
但在实际开发中会有下面一种状况:
//设置锁1秒过去 redissonLock.lock("redisson", 1); /** * 业务逻辑须要咨询2秒 */ redissonLock.release("redisson"); /** * 线程1 进来得到锁后,线程一切正常并无宕机,但它的业务逻辑须要执行2秒,这就会有个问题,在 线程1 执行1秒后,这个锁就自动过时了, * 那么这个时候 线程2 进来了。那么就存在 线程1和线程2 同时在这段业务逻辑里执行代码,这固然是不合理的。 * 并且若是是这种状况,那么在解锁时系统会抛异常,由于解锁和加锁已经不是同一线程了,具体后面代码演示。 */
因此这个时候看门狗
就出现了,它的做用就是 线程1 业务尚未执行完,时间就过了,线程1 还想持有锁的话,就会启动一个watch dog后台线程,不断的延长锁key的生存时间。
注意
正常这个看门狗线程是不启动的,还有就是这个看门狗启动后对总体性能也会有必定影响,因此不建议开启看门狗。
这个不用多说,主要是若是你的业务逻辑复杂的话,经过封装在lua脚本中发送给redis,并且redis是单线程的,这样就保证这段复杂业务逻辑执行的原子性。
Redisson能够实现可重入加锁机制的缘由,我以为跟两点有关:
一、Redis存储锁的数据类型是 Hash类型 二、Hash数据类型的key值包含了当前线程信息。
下面是redis存储的数据
这里表面数据类型是Hash类型,Hash类型至关于咱们java的 <key,<key1,value>>
类型,这里key是指 'redisson'
它的有效期还有9秒,咱们再来看里们的key1值为078e44a3-5f95-4e24-b6aa-80684655a15a:45
它的组成是:
guid + 当前线程的ID。后面的value是就和可重入加锁有关。
举图说明
上面这图的意思就是可重入锁的机制,它最大的优势就是相同线程不须要在等待锁,而是能够直接进行相应操做。
Redis分布式锁会有个缺陷,就是在Redis哨兵模式下:
客户端1
对某个master节点
写入了redisson锁,此时会异步复制给对应的 slave节点。可是这个过程当中一旦发生 master节点宕机,主备切换,slave节点从变为了 master节点。
这时客户端2
来尝试加锁的时候,在新的master节点上也能加锁,此时就会致使多个客户端对同一个分布式锁完成了加锁。
这时系统在业务语义上必定会出现问题,致使各类脏数据的产生。
缺陷
在哨兵模式或者主从模式下,若是 master实例宕机的时候,可能致使多个客户端同时完成加锁。
说明
这篇博客主要是根据本身的开发经验,同时也在网上找了许多资料后整理的,若是哪里有写的不对,但愿多多指点。万分感激!
只要本身变优秀了,其余的事情才会跟着好起来(中将5)