Redisson分布式锁
使用
两个常用API
tryLock:非阻塞锁,如果不设置waitTime的话,就直接return了
lock:阻塞锁,线程获取不到锁,会阻塞住
为什么基于lua脚本实现而不是事务?
两者都是可以保证原子性的,但
可重入锁?
redisson是基于redis的数据结构hash去实现可重入锁的。key为lock,field为线程名,value为count。这个
count就是用来表示一个锁被同一线程持有的情况
加锁流程:就是会先判断锁是否被当前线程持有或者说有没有线程持有,不是就表示加锁失败,是的话,就
count++;

解锁流程:每次执行完毕就count–。直到count==0,就把其key删除掉,表示锁完全释放
加锁流程和解锁流程都是基于lua脚本实现的

不止hash结构?
1.字符串拼接,把count拼进去
2.redis那里还是使用string,服务内部通过concurrentHashMap保存:key为线程唯一标识,value为锁
计数器
1 | // 用于保存线程对应的锁和重入次数 |
可阻塞锁,可重试锁?
Redisson的可阻塞锁是基于Redis的发布订阅模式来实现等待,唤醒,获取锁失败的重试机制的
获取锁失败不是直接重试or返回,而是订阅一下,然后等待
当获取锁成功的线程释放锁后,就会发布一条消息
其他线程就会收到这条消息,从而重新获取锁,获取失败就会继续等待
但也不是无限等待,超过一定时间,就不会继续等了,而是会返回false(针对于tryLock())
联锁?
对于分布式锁在主从架构中的锁丢失问题,Redisson提供了一种联锁机制。它要求Redis使用多主多从或者多
主,那么只有所有Redis主节点都上锁成功,才算上锁成功。这样的话,如果某个主节点宕机了,那么其他主
节点也是有锁的数据的,新线程想要给所有主节点加锁,那还是会加锁失败的
ps:主从架构中的锁丢失问题:当主节点setnx成功后,这时候来没来得及同步就挂了。那么这时候就会重新
选主,但这时候新的主节点是没锁数据的,服务器就会认为锁已经释放了,导致锁的互斥性失效了。
红锁?
但对于联锁而言,还可能会存在以下问题
1.所有主节点都得上锁,若某个主节点由于网络原因,导致加锁时间长,加锁失败
2.或者某个主节点宕机了,一直加锁失败
那么如果出现以上情况,就会导致一直加锁失败,失败概率很高,而且加锁失败后是要回滚所有Redis主节点
的数据的,性能很差的。
那么基于以上问题………………
Redis官方提供了一种红锁机制,也要求Redis要多主部署,但加锁时只要半数以上加锁成功就OK了。如果
当前线程加锁加到半数以上,那么其他线程就不可能加锁加到了半数以上了,那么这样就满足了互斥性
但redLock也是有很大问题的,
主要原因是Redis创始人不推荐在严格一致性的分布式情况下使用它
有什么可以替代的吗?业界无公认的方案
我个人的思考
1.使用单实例的Redis锁,虽然会有单节点故障
2.业务做好唯一性校验
3.使用强一致性组件来实现分布式锁,如zookeeper
分布式锁检验死锁?
观察看门狗线程,如果出现某两个看门狗线程存活时间过长,则这两个看门狗对应的分布式锁可能产生死锁