【分布式缓存系列】集群环境下Redis分布式锁的正确姿势

一、前言   在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况: 客户端1在Redis的master节点上拿到了锁 Master宕机了,存储锁的key还没有来得及同步到Slave上 master故障,发生故障转移,slave节点升级为master节点 客户端2从新的Master获取到了对应同一个资源的锁   于是,客户端1和客户端2同时持有了同一个资源的锁。锁的安全性被打破了。针对这个问题。Redis作者antirez提出了RedLock算法来解决这个问题 二、RedLock算法的实现思路   antirez提出的redlock算法实现思路大概是这样的。   客户端按照下面的步骤来获取锁: 获取当前时间的毫秒数T1。 按顺序依次向N个Redis节点执行获取锁的操作。这个获取锁的操作和上一篇中基于单Redis节点获取锁的过程相同。包括唯一UUID作为Value以及锁的过期时间(expireTime)。为了保证在某个在某个Redis节点不可用的时候算法能够继续运行,这个获取锁的操作还需要一个超时时间。它应该远小于锁的过期时间。客户端向某个Redis节点获取锁失败后,应立即尝试下一个Redis节点。这里失败包括Redis节点不可用或者该Redis节点上的锁已经被其他客户端持有。 计算整个获取锁过程的总耗时。即当前时间减去第一步记录的时间。计算公司为T2=now()- T1。如果客户端从大多数Redis节点(>N/2 +1)成功获取到锁。并且获取锁总共消耗的时间小于锁的过期时间(即T2 { RedisDistributedRedLock redisDistributedRedLock = null; RedissonClient redissonClient = null; try { redissonClient = Redisson.create(config); redisDistributedRedLock = new RedisDistributedRedLock(redissonClient, "stock_lock"); redisDistributedRedLock.acquire(); secskill(); System.out.println(Thread.currentThread().getName() + "正在运行"); } finally { if (redisDistributedRedLock != null) { redisDistributedRedLock.release(null); } redissonClient.shutdown(); } }; for (int i = 0; i < 10; i++) { Thread t = new Thread(runnable); t.start(); } } 复制代码   具体的运行结果,如下图所示: 四、总结   到此,基于Redis实现分布式锁的就告一段落了,由于分布式锁的实现方式主要有:数据库锁的方式、基于Redis实现和基于Zookeeper实现。接下来的一篇文章将介绍基于Zookeeper分布式锁的正确姿势。   本文所有代码地址:https://github.com/learninghard-lizhi/common-util 如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏我一杯咖啡【物质支持】,也可以点击右下角的【店长推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力 分类: 分布式专题https://www.cnblogs.com/zhili/p/redLock_DistributedLock.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信