实现Redis的分布式锁,除了自己基于redis client原生api来实现之外,还可以使用开源框架:Redission

Redisson是一个企业级的开源Redis Client,也提供了分布式锁的支持。

回想一下上一篇文章《基于Redis实现分布式锁》说的,如果自己写代码来通过redis设置一个值,是通过下面这个命令设置的。

SET anyLock unique_value NX PX 30000

这里设置的超时时间是30s,假如我超过30s都还没有完成业务逻辑的情况下,key会过期,其他线程有可能会获取到锁。

这样一来的话,第一个线程还没执行完业务逻辑,第二个线程进来了也会出现线程安全问题。所以我们还需要额外的去维护这个过期时间,太麻烦了~

我们来看看redisson是怎么实现的?先感受一下使用redission的爽:

过程:

就是这么简单,我们只需要通过它的api中的lock和unlock即可完成分布式锁,他帮我们考虑了很多细节:

1:redisson所有指令都通过lua脚本执行,redis支持lua脚本原子性执行

2:redisson设置一个key的默认过期时间为30s,如果某个客户端持有一个锁超过了30s怎么办? redisson中有一个watchdog的概念,翻译过来就是看门狗,它会在你获取锁之后,每隔10秒帮你把key的超时时间设为30s 这样的话,就算一直持有锁也不会出现key过期了,其他线程获取到锁的问题了。

3:redisson的“看门狗”逻辑保证了没有死锁发生。 (如果机器宕机了,看门狗也就没了。此时就不会延长key的过期时间,到了30s之后就会自动过期了,其他线程可以获取到锁)

示例代码:

// 加锁以后30秒钟自动解锁

// 无需调用unlock方法手动解锁

redissionLock.lock(30, TimeUnit.SECONDS);

其实上面截图的代码

应该改为下面这个才好,这样子看门狗才能真正生效,不然上面的代码会造成30秒后,锁会自动解锁的。

redissionLock.lock();

但是我们除了要考虑客户端要怎么实现分布式锁之外,还需要考虑redis的部署问题。

redis有三种部署方式:

1:单机模式

如果采用单机部署模式,会存在单点问题,只要redis故障了,加锁就不行了。

2:master-slave + sentinel 哨兵模式

采用master-slave模式,即便通过sentinel做了高可用(Master 宕机后立马切换Slave作为新的Master),但是由于节点之间是采用异步通信的方式,如果A客户端刚刚在 Master 节点上加了锁,但是数据还没被同步到 Salve,这时 Master 节点挂了,它上面的锁就没了,这时进行主从切换,等新的 Master 出来后,B客户端此时就可以再获取同样的锁,出现一把锁被拿到了两次的场景,从而导致系统出现脏数据。

3:redis cluster 集群模式

采用redis cluster集群模式,比如3主3从,主备切换。但是由于节点之间是采用异步通信的方式,如果A客户端刚刚根据路由规则在其中一台Master 节点上加了锁,但是数据还没被同步到 它的Salve,这时 这台Master 节点挂了,它上面的锁就没了,这时进行主备切换,等新的 Master 出来后,B客户端此时就可以再获取同样的锁,出现一把锁被拿到了两次的场景,从而导致系统出现脏数据。

为了解决上面的问题,Redis 的作者提出了名为 Redlock 的算法。

在 Redis 的分布式环境中,我们假设有 N 个 Redis Master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。(要注意这点)

前面已经描述了在单点 Redis 下,怎么安全地获取和释放锁,我们确保将在 N 个实例上使用此方法获取和释放锁。

在下面的示例中,我们假设有 5 个完全独立的 Redis Master 节点,他们分别运行在 5 台服务器中,可以保证他们不会同时宕机。

从官网上我们可以知道,一个客户端如果要获得锁,必须经过下面的五个步骤:

步骤描述来源:

http://redis.cn/topics/distlock.html

1:获取当前Unix时间,以毫秒为单位。

2:依次尝试从N个实例,使用相同的key和随机值获取锁。在步骤2,当向Redis设置锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。

3:客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。

4:如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功)。

通过上面的步骤我们可以知道,只要大多数的节点可以正常工作,就可以保证 Redlock 的正常工作。这样就可以解决前面单点 Redis 的情况下我们讨论的节点挂掉,由于异步通信,导致锁失效的问题。

延迟重启

但是,还是不能解决故障重启后带来的锁的安全性的问题。你想一下下面这个场景,这个场景让redis的创始人提出了“延迟重启”的概念。

红锁之redis持久化失败后重启场景

我们一共有 A、B、C 这三个节点。

客户端 1 在 A,B 上加锁成功。C 上加锁失败。

这时节点 B 崩溃重启了,但是由于持久化策略导致客户端 1 在 B 上的锁没有持久化下来。

客户端 2 发起申请同一把锁的操作,在 B,C 上加锁成功。

这个时候就又出现同一把锁,同时被客户端 1 和客户端 2 所持有了。

(接下来又得说一说Redis的持久化策略了,全是知识点啊,朋友们)

比如,Redis 的 AOF 持久化方式默认情况下是每秒写一次磁盘,即 fsync 操作,因此最坏的情况下可能丢失 1 秒的数据。

当然,你也可以设置成每次修改数据都进行 fsync 操作(fsync=always),但这会严重降低 Redis 的性能,违反了它的设计理念。(我也没见过这样用的,可能还是见的太少了吧。)

而且,你以为执行了 fsync 就不会丢失数据了?天真,真实的系统环境是复杂的,这都已经脱离 Redis 的范畴了。上升到服务器、系统问题了。

所以,根据墨菲定律,上面举的例子:由于节点重启引发的锁失效问题,总是有可能出现的。

为了解决这一问题,Redis 的创始人又提出了延迟重启(delayed restarts)的概念。

意思就是说,一个节点崩溃后,不要立即重启它,而是等待一定的时间后再重启。等待的时间应该大于锁的过期时间(TTL)。这样做的目的是保证这个节点在重启前所参与的锁都过期。相当于把以前的帐勾销之后才能参与后面的加锁操作。

看门狗和红锁

看门狗和红锁和延迟重启其实都是redis的分布式锁的概念,真正用redis去实现是比较困难的,所以我们一般用reddission去实现,人家已经帮我们做好了,只要学会用它的代码就行。

这个红锁以及延迟重启思路的加锁算法在Redisson的红锁RedissonRedLock对象上面实现了,接下来我们来看是怎么用Reddsion实现的

该RedissonRedLock对象也可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例。

红锁之有看门狗手动解锁方式:

Config config1 = new Config();

config1.useSingleServer().setAddress("redis://172.0.0.1:5378").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient1 = Redisson.create(config1);

Config config2 = new Config();

config2.useSingleServer().setAddress("redis://172.0.0.1:5379").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient2 = Redisson.create(config2);

Config config3 = new Config();

config3.useSingleServer().setAddress("redis://172.0.0.1:5380").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient3 = Redisson.create(config3);

/**

* 获取多个 RLock 对象

*/

RLock lock1 = redissonClient1.getLock(lockKey);

RLock lock2 = redissonClient2.getLock(lockKey);

RLock lock3 = redissonClient3.getLock(lockKey);

/**

* 根据多个 RLock 对象构建 RedissonRedLock (最核心的差别就在这里)

*/

RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {

//有看门狗,业务没执行完可以不停的延长锁的过期时间

boolean res = redLock.lock();

if (res) {

//成功获得锁,在这里处理业务

}

} catch (Exception e) {

throw new RuntimeException("aquire lock fail");

}finally{

//无论如何, 最后都要解锁

redLock.unlock();

}

大家都知道,如果负责储存某些分布式锁的某些Redis节点宕机以后,而且这些锁正好处于锁住的状态时,这些锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。

//给lock1,lock2,lock3加锁

RedissonRedLock lock=newRedissonRedLock(lock1, lock2, lock3);

红锁之无看门狗自动解锁方式1:

//如果没有手动解开的话,10秒钟后将会自动解开

lock.lock(10,TimeUnit.SECONDS);

...

lock.unlock();

红锁之无看门狗自动解锁方式2:

//为加锁等待100秒时间,并在加锁成功10秒钟后自动解开

booleanres=lock.tryLock(100,10,TimeUnit.SECONDS);

...

lock.unlock();

下面代码采用的是红锁之无看门狗自动解锁方式2

Config config1 = new Config();

config1.useSingleServer().setAddress("redis://172.0.0.1:5378").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient1 = Redisson.create(config1);

Config config2 = new Config();

config2.useSingleServer().setAddress("redis://172.0.0.1:5379").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient2 = Redisson.create(config2);

Config config3 = new Config();

config3.useSingleServer().setAddress("redis://172.0.0.1:5380").setPassword("a123456").setDatabase(0);

RedissonClient redissonClient3 = Redisson.create(config3);

/**

* 获取多个 RLock 对象

*/

RLock lock1 = redissonClient1.getLock(lockKey);

RLock lock2 = redissonClient2.getLock(lockKey);

RLock lock3 = redissonClient3.getLock(lockKey);

/**

* 根据多个 RLock 对象构建 RedissonRedLock (最核心的差别就在这里)

*/

RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {

/**

* 尝试获取锁

* waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败

* leaseTime  锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)

*/

boolean res = redLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);

if (res) {

//成功获得锁,在这里处理业务

}

} catch (Exception e) {

throw new RuntimeException("aquire lock fail");

}finally{

//无论如何, 最后都要解锁

redLock.unlock();

}

Reddsion的红锁有一个宕机细节

如果采用红锁之有看门狗手动解锁方式,按照上面的“红锁之redis持久化失败后重启场景”,有3个节点ABC,其实我们已经解决了延迟重启问题,但是这时候,只有AC节点在正常运行,B节点还未重启的情况:

客户端2要获取一样的锁,是获取不了的,因为AB节点获取失败,C节点就算获取成功,也是只有1个获取成功,所以会获取不了一样的锁,这点是正常的。

客户端2要获取不一样的锁,AC可以获取得到,还是有办法的,这点是正常的。

这但是如果这时候C节点也挂了,剩下一个A节点有锁,

这时候想要获取一样的锁,不成功,这是正常的,等到这个锁解锁了,其他节点就可以重启了!

这时候想要获取不一样的锁,不成功,因为只剩下1个正常的节点!

比如5个节点的话,ABCDE,ABC加锁成功,DE加锁失败,这时候B又挂了,剩下AC有锁而已,DE没有锁。

客户端2要获取一样的锁,是获取不了的,因为ABC节点获取失败,DC节点就算获取成功,也是只有2个获取成功,所以会获取不了一样的锁,这点是正常的。

客户端2要获取不一样的锁,ACDE可以获取得到,还是有办法的,这点是正常的。

但是如果这时候C节点也挂了,剩下一个A节点有锁,DE没锁,

这时候想要获取一样的锁,不成功,这是正常的,等到这个锁解锁了,其他节点就可以重启了!

这时候想要获取不一样的锁,可能会成功,因为有3个正常的节点!

比如6个节点的话,ABCDEF,ABCD加锁成功,EF加锁失败,这时候B又挂了,剩下ACD有锁而已,EF没有锁。

客户端2要获取一样的锁,是获取不了的,因为ABCD节点获取失败,EF节点就算获取成功,也是只有2个获取成功,所以会获取不了一样的锁,这点是正常的。

客户端2要获取不一样的锁,ACDEF可以获取得到,还是有办法的,这点是正常的。

但是如果这时候C节点也挂了,剩下一个AD节点有锁,EF没锁,

这时候想要获取一样的锁,不成功,这是正常的,等到这个锁解锁了,其他节点就可以重启了!

这时候想要获取不一样的锁,可能会成功,因为有4个正常的节点!

但是如果这时候CD节点都挂了,剩下一个A节点有锁,EF没锁,

这时候想要获取一样的锁,不成功,这是正常的,等到这个锁解锁了,其他节点就可以重启了!

这时候想要获取不一样的锁,不会成功,因为只有3个正常的节点!

总结:如果大多数节点,进入了等待。就会导致系统的不可用,因为系统在业务执行完程序手动解锁的时间内(或者TTL时间内)任何锁(一样的锁和不一样的锁)都将无法加锁成功,其实等待 执行完手动解锁或者TTL时间内,其他节点自动重启就没事了,所以没有太大的问题!

Reddsion的红锁有一个释放锁细节

释放锁的时候是要向所有节点发起释放锁的操作的。这样做的目的是为了解决有可能在加锁阶段,这个节点收到加锁请求了,也set成功了,但是由于返回给客户端的响应包丢了,导致客户端以为没有加锁成功。所有,释放锁的时候要向所有节点发起释放锁的操作。

红锁算法最重要的问题来了!!!也算要注意红锁算法的bug所在吧!

如果采用“看门狗失效红锁自动解锁方式1和2”,

问题1:

1、如果A客户端获取到了锁,然后它的A线程GC暂停了,经过一段时间,锁自动解锁了

2、此时B客户端来获取一样的锁,这时候A线程GC恢复了,此时A线程继续执行他的业务代码,B客户端的B线程也同时执行它的业务代码

3、这时候会导致同一时间内两个客户端有同一把锁,没有满足同一时间内一个锁只能有一个客户端持有的原则,所以会导致系统出现脏数据

从客户端的角度来看,就是这玩意不靠谱啊,你给我一把锁,我还没用呢,你就过期了,但是我还以为我能用,哪还知道其他人也有跟我一样的锁,这下好了这个锁同时被两个人用,这是不靠谱的做法!

(我觉得无法反驳)

问题2:

1、客户端 1 向 Redis 节点 A, B, C, D, E 发起锁请求。

2、各个 Redis 节点已经把请求结果返回给了客户端 1,但客户端 1 在收到请求结果之前进入了长时间的 GC 阶段。

3、长时间的 GC,导致在所有的 Redis 节点上,锁过期了。

4、客户端 2 在 A, B, C, D, E 上申请并获取到了锁。

5、客户端 1 从 GC 阶段中恢复,收到了前面第 2 步来自各个 Redis 节点的请求结果。客户端 1 认为自己成功获取到了锁。

6、客户端 1 和客户端 2 现在都认为自己持有了锁。

我觉得可以反驳,这种情况其实对于 Redlock 是没有影响的,因为在第 5 步,客户端 1 从 GC 阶段中恢复过来以后,在 Redlock 算法中,如果取到了锁,key 的真正有效时间等于有效时间减去获取锁所使用的时间,客户端1通过这个检查发现锁已经过期了,不会再认为自己成功获取到锁了)

对于问题1问题2,redis创始人有反驳,我只看得懂能够反驳问题2,反驳不了问题1。

redis创始人的反驳:“Redlock 没有提供类似于fencing机制那样的单调递增的令牌,但是也有一个随机串,把这个随机串当做token,也可以达到同样的效果啊。当需要和共享资源交互的时候,我们检查一下这个token是否发生了变化,如果没有再执行“获取-修改-写回”的操作”

如果有人能理解这段话能反驳问题1的话,麻烦在文章下面评论一下。让我好好理解一下,谢谢!(后面我跟程序圈的why神聊过,redis的创始人是没法反驳问题1的,只能反驳问题2)

问题3:时钟发生跳跃(关于马丁哥的疑问)

1:客户端 1 从 Redis 节点 A, B, C 成功获取了锁。由于网络问题,无法访问 D 和 E。

2:节点 C 上的时钟被人修改了或者从NTP服务收到了一个大的时钟更新事件,导致它上面维护的锁过期了。

3:客户端 2 从 Redis 节点 C, D, E 成功获取了同一个资源的锁。由于网络问题,无法访问 A 和 B。

4:现在,客户端 1 和客户端 2 都认为自己持有了锁。

这样的场景是可能出现的,因为 Redlock 严重依赖系统时钟,所以一旦系统的时间变得不准确了,那么该算法的安全性也就得不到保障了。

延迟启动方案,延迟启动还不是依赖于合理准确的时间度量,如果时钟不准确,该算法的安全性也一样没有保障。

总结:

1:运维人员手动修改了系统时钟。

2:从NTP服务收到了一个大的时钟更新事件。

redis创始人进行了回击:

第一点这个运维人员手动修改时钟,属于人为因素,这个我也没办法啊,人家就是要搞你,怎么办?加强管理,不要这样做。

第二点从NTP服务收到一个大的时钟更新,对于这个问题,需要通过运维来保证,通过正确配置NTP。需要将大的时间更新到服务器的时候,应当采取少量多次的方式。多次修改,每次更新时间尽量小。

关于这个地方的争论,就看你是信马丁哥的时间一定会跳跃,还是redis创始人的时间跳跃我们也是可以处理的。

redis创始人的想法:他是同意大的系统时钟跳跃会造成 Redlock 失效的。在这一点上,他与马丁哥的观点的不同在于,他认为在实际系统中是可以通过好的运维方式避免大的时钟跳跃的。

对于问题123,其实Redission使用“看门狗生效红锁方式”就能解决,A线程GC的时候,看门狗一直续锁的过期时间,使这个锁不会过期,而且确保系统时钟不要出现大的时间跳跃(比如人为修改系统时钟或者收到大的时钟更新时间的话,就正确配置NTP,其实这里的时间跳跃不要超过20秒就好,因为每个10秒,看门狗会去自动更新过期时间为30秒,不过这个30秒也是可以设置的,可以更改为60甚至更多,改为60的话,就是60/3=20,每隔20秒去重置过期时间),基本可以保证redission的分布式锁的零失误率,系统不出现脏数据!!!

还有就是各个redis应用不要大多数宕机,这会导致系统一时间没法加锁,但是不会导致系统出现脏数据。

但是其实上面这个方式,还有一个bug的存在,非常极端的条件。

问题4:看门狗gc暂停场景

1、如果A客户端获取到了锁,然后它的A线程GC暂停了,它的看门狗线程也GC暂停,经过一段时间,锁自动解锁了

2、此时B客户端来获取一样的锁,这时候A线程GC恢复了,它的看门狗线程GC没有恢复(其实此时恢复与不恢复都没关系吧,比较锁都过期了,而且别的客户端也一样拿到一样的锁了),此时A线程继续执行他的业务代码,B客户端的B线程也同时执行它的业务代码

3、这时候会导致同一时间内两个客户端有同一把锁,没有满足同一时间内一个锁只能有一个客户端持有的原则,所以会导致系统出现脏数据

所以在使用“看门狗生效红锁方式”的这种方式,保证时钟不会出问题,如果出现“看门狗gc暂停”场景,reddission的红锁算法也是不靠谱的,在极端条件下还是会出现bug的!

或者可以考虑,只使用redis单机模式的reddission分布式锁就好了,简单而且效率高。用 Redlock 太重。

但是单机模式的话,有一个场景:

A客户端拿到锁,然后 此时A客户端的线程GC暂停了,看门狗GC不GC没有关系,此时单机redis也宕机了,等到锁过期了,我们重启了redis,此时B客户端的拿到一样的锁,此时A客户端的线程GC恢复了,继续执行他的业务,此时同一个时间有两个客户端拿到同一把锁!

解决方法:

redis宕机的时候,别那么快去重启redis,防止有线程在GC暂停中,应该等线程超时之后再去重启,或者你的方法里面有事务,等到事务超时再去重启redis应用!

总结:

redis暂时也没实现这种令牌思维,所以采用redission分布式锁,用哪种都可以,

红锁:只能更好的避免出现脏数据的几率,而且不会出现单点问题。

单机redis:会出现单点故障,但是小心点处理重启时间,也不会出现脏数据。

主从哨兵模式,cluster模式:宕机的话比较容易出现脏数据。

其实用redis做分布式锁,在极端环境下,是无法完全保证不出现脏数据。

对付脏数据的方法:

其实多下了订单的话超出了库存,可以在业务层面去解决,比如多预留一些商品库存,把多下的订单商品也进行发货,

库存表如果有库存总数量,维护的时候就要把库存的总数量进行修改,剩余库存总数量就不用更改,避免脏数据。

,或者将超出库存多下的订单,回滚,设置为无效,修复脏数据,其中的数据修改细节,每个系统的都不一样,有些系统还可能涉及到积分还有其他会员等级之类的变动,所以修复脏数据,应该依照自己的系统情况来做。

redis分布式锁在这个地方有一个缺点没做好,也是之前马丁哥所说的例子:

也就是说 GC 恢复了,但是你其实已经锁已经失效了,但是你还觉得自己是有效的,然后业务继续执行,殊不知道还有人也拿到这把一样的锁,跟你一起在执行。

要实现这一目标,可以采用fencing令牌思维。

1、客户端 1 获得一个具有超时时间的锁的同时得到了令牌号 33,但随后陷入了一个长时间的暂停直到锁到期。

2、这时客户端2已经获得了锁和令牌号 34 ,然后发送写请求(以及令牌号 34 )到存储服务。

3、接下来客户端 1 恢复过来,并以令牌号 33 来尝试写入,存储服务器由于记录了最近已经完成了更高令牌号(34 ),因此拒绝令牌号 33 的写请求。

这种版本号的机制,让我不禁想起了 Zookeeper。当使用 ZK 做锁服务时,可以用事务标识 zxid 或节点版本 cversion 来充当 fencing 令牌,这两个都可以满足单调递增的要求。

长发哥在书中也说到了:在服务端检查令牌可能看起来有点复杂,但是这其实是推荐的正确的做法:系统服务不能假定所有的客户端都表现的符合预期。从安全角度讲,服务端必须防范这种来自客户端的滥用。

对于redis的分布式锁而言,优缺点:

1、它获取锁的方式简单粗暴,获取不到锁直接不断尝试获取锁,比较消耗性能。

2、另外来说的话,redis的设计定位决定了它的数据并不是强一致性的,在某些极端情况下,可能会出现问题。锁的模型不够健壮

3、即便使用redlock算法来实现,在某些复杂场景下,也无法保证其实现100%没有问题,关于redlock的讨论可以看How to do distributed locking

4、但是另一方面使用redis实现分布式锁在很多企业中非常常见,而且大部分情况下都不会遇到所谓的“极端复杂场景”

所以使用redis作为分布式锁也不失为一种好的方案,最重要的一点是redis的性能很高,可以支撑高并发的获取、释放锁操作。

另外还有一种分布式锁是zookeeper分布式锁

对于zookeeper的分布式锁而言,优缺点:

1、zookeeper天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。

2、如果获取不到锁,只需要添加一个监听器就可以了,不用一直轮询,性能消耗较小。

3、如果有较多的客户端频繁的申请加锁、释放锁,对于zk集群的压力会比较大。

建议:

如果注重数据的准确性,数据不允许有一点错误:可以用zookeeper分布式锁解决,可以保证绝对不出问题,但是性能比redis差。

如果能容忍redis宕机问题导致reddsion分布式锁出现的锁失效问题,从而可能会导致数据出现问题,则可以还是使用redis。

如果使用“看门狗生效红锁方式”,则只需要确保系统时钟不要出现大的跳跃就可以保证零失误,极端条件下出现脏数据的话,就按照自己的系统的情况去处理脏数据吧!

基于Redission实现分布式锁相关推荐

  1. redission java_Java注解如何基于Redission实现分布式锁

    这篇文章主要介绍了Java注解如何基于Redission实现分布式锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.定义注解类 @Target( ...

  2. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  3. 基于redis实现分布式锁思考

    分布式锁 基于redis实现分布式锁思考几个问题??? synchronized锁为什么不能应用于分布式锁? synchronized虽然能够解决同步问题,但是每次只有一个线程访问,并且synchro ...

  4. Redission实现分布式锁完美方案 以及 Lua 脚本浅谈

    Redission实现分布式锁完美方案 以及 Lua 脚本浅谈 文章目录 Redission实现分布式锁完美方案 以及 Lua 脚本浅谈 前言 常见分布式锁方案对比 分布式锁需满足四个条件 Redis ...

  5. etcd 笔记(08)— 基于 etcd 实现分布式锁

    1. 为什么需要分布式锁? 在分布式环境下,数据一致性问题一直是个难点.分布式与单机环境最大的不同在于它不是多线程而是多进程.由于多线程可以共享堆内存,因此可以简单地采取内存作为标记存储位置.而多进程 ...

  6. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  7. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  8. redis系列:基于redis的分布式锁

    一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...

  9. 基于 Redis 的分布式锁到底安全吗?

    [完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...

最新文章

  1. 种子文件多服务器,使用bitcomet制作torrent文件 [BitComet]
  2. 牛客华为机试第5题python
  3. C++ MFC控制台输出调试信息
  4. Java设计模式(二十):中介者设计模式
  5. 信息保真度准则_设计保真度的新的非科学公式
  6. [转载] 常用应届生Java开发笔试面试题(更新中)
  7. 解决ORA-01578错误一例
  8. good nice fine well区别
  9. 网络营销之怎样推广博客
  10. python入门学校_如何学习Python,以及新手如何入门?
  11. 脑电EEG代码开源分享 【1.前置准备-静息态篇】
  12. 5个步骤搞定protoc环境安装
  13. ApacheCN 活动汇总 2019.7.12
  14. 风险评估(Risk Assessment)
  15. 冬令时 java_java-时间处理夏令时冬令时跨时区问题处理
  16. 必应壁纸php,PHP版Bing壁纸下载源码
  17. 计算机技术工种技师,中级及以上专业技术职务或者具有技师以上职业资格具体包括哪些职务和资格...
  18. Appium+python自动化3-启动淘宝app(转)
  19. IBMX3650M4服务器重装window系统
  20. 低潮是人生最佳升值期

热门文章

  1. 纬地道路纵断面设计教程_直通车 | 中交一公局公路勘察设计院有限公司招聘公告...
  2. Java: static,final,代码块 的详解
  3. sql和python还有c语言_TIOBE 4 月排行榜:SQL 进入前十,Python 继续攀升
  4. PHP对接支付 alipay支付
  5. Nginx+Lua 实现灰度发布详细步骤
  6. 利用osp.join()拼接文件名,利用f“{}“强制类型转换,利用osp.basename得到路径后面的文件名
  7. python适合在什么平台运行-Python 可以在多种平台运行,
  8. stata软件不出图_Stata软件的图形绘制—2
  9. 论文阅读 (78):FlowNet: Learning Optical Flow with Convolutional Networks
  10. 自然语言处理领域的数据增广方法