RedLock 由来原理

redis提供了一个分布式锁的规范算法 Redlock java版本:Redisson :https://github.com/redisson/redisson

锁的特点:独享(互斥)、无死锁(持有锁的客户端崩溃或者网络分裂,锁仍然可以使用)、容错(大部分节点活着可用)

第一个阶段:

redis设置锁,就是创建一个key,然后针对整个key设置过期时间,执行完,删除这个key,这里面有个问题,redis挂了怎么办?增加一个从节点?redis的主从是异步的,如果主挂了,还是有问题。(客户端A从master获取到锁,然后master挂了,slave成为主,这时候客户端B获取到锁,锁失效)

第二个阶段:

使用单个redis实例上锁 这种方式保证redis在大多数场景下总是可用的

使用redis的特性setnx

SET resource_name my_random_value NX PX 30000

只有key存在才能设置成功,多个客户端竞争的key resource_name ,每个客户端的my_random_value不能相同,30000 过期时长,PX过期属性

之后执行完业务逻辑,删除我自己创建的锁,使用lua脚本,执行是原子性,这里要校验一下存的值value和当前客户端存放的值相同,才能删除,防止删了别人的锁,这个my_random_value一定要是唯一的,

if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end

Redlock算法

在redis的分布式环境中,假设有N个Master节点,彼此之间是独立的,通过同时操作多台加锁解决,现在redis需要加锁,就在这N个节点执行加锁或者释放锁的时间,具体操作和上面单个redis处理一样,具体执行的步骤如下:

1.获取当前的时间,以毫秒为单位;

2.依次或者并发尝试,调用N个实例上使用锁,使用相同的key设置锁,客户端与redis连接超时时间要小于锁的过期时间,不然有的节点锁已经过期了,你还没拿到锁,还在等待是没有意义的。如果锁在规定的时间之内没有获取到锁,就尝试另外一台redis;

3.客户端使用时间为当前时间,减去开始获取锁的时间,就是获取锁的使用时间t1,当且仅当这里的大多数redis获取到锁(至少是N/2+1,过半),同时t1<过期时间,获取锁成功。

4.获取锁成功,那么业务执行的时间为过期时间减t1,就是真正执行的时间;(这里要注意,锁的失效时间和业务执行时间之间的关系)

5.如果获取锁失败(获取锁超时或者获取锁的数量少于N/2+1),客户端需要释放锁。

失败重试

多个客户端,同时获取锁都获取到部分,没有过半,则生成一个随机等待的时间,之后再次执行获取锁,还有获取锁失败的客户端要尽快的释放锁,让其它的尽快获取到,多个客户端获取锁,要并发的请求,获取的速度足够快失败的次数就少一点。

释放锁

向所有节点发送释放指令,不用关心之前时候获得过锁,使用lua脚本

如果我们使用redis锁,aof落盘方式使用fsync=always,提高锁的安全性,但是降低了性能

这里还有一个问题,如果redis挂了,然后重启,这时候可能clientA获取到了锁,clientB也获取到了,这时候我们使用redis的延迟重启(超过这个TTL),保证A锁过期之后再重启成功,可以避免这个问题,但是会有性能上的问题。

产生死锁场景

如果一个业务机器获取到redis锁,在执行的过程中如果业务机器挂了,这时候就会导致锁一直在这个业务机器没有释放,导致死锁。

解决死锁方法 可重入锁

redisson,为了解决这个问题设置一个lockWatchdogTimeout参数,看门狗检查超时时间,默认为30秒这个可以通过Config.lockWatchdogTimeout 参数进行设置,这个作用保证在客户端执行业务过程中,不会因为业务还没有执行完成就过期。如果业务没有执行完,锁快到期不断的进行续期。

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

// 加锁以后10秒钟自动解锁
// 无需调用unlock方法手动解锁
lock.lock(10, TimeUnit.SECONDS);// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
if (res) {try {...} finally {lock.unlock();}
}

RLock对象完全符合Java的Lock规范。也就是说只有拥有锁的进程才能解锁,其他进程解锁则会抛出IllegalMonitorStateException错误。但是如果遇到需要其他进程也能解锁的情况,请使用分布式信号量Semaphore 对象.

红锁(RedLock)

如果因为单个redis节点宕机或者主从的问题导致线程安全的问题,使用redlock解决

基于Redis的Redisson红锁RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例。

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();

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

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

RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 给lock1,lock2,lock3加锁,如果没有手动解开的话,10秒钟后将会自动解开
lock.lock(10, TimeUnit.SECONDS);// 为加锁等待100秒时间,并在加锁成功10秒钟后自动解开
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();

附录:

REDIS distlock -- Redis中国用户组(CRUG)

8. 分布式锁和同步器 · redisson/redisson Wiki · GitHub

汪~汪~汪~redisson的WatchDog是如何看家护院的? - 菜鸟学院

Redis锁 - RedLock相关推荐

  1. Redis分布式锁(Redlock官方文档的理解)

    Redis分布式锁(Redlock官方文档的理解) 我github博客原文 官网解释 分布式锁在许多不同进程下需要对共享资源进行互斥操作的环境下,十分需要 Redis作者提出了 Redlock 算法 ...

  2. 分布式Redis的分布式锁 Redlock

    引言 之前自己在用redis来实现分布式锁的时候都是基于单个Redis实例,也就是说Redis本身是有单点故障的,Redis的官方文档介绍了一种"自认为"合理的算法,Redlock ...

  3. redlock java_分布式Redis的分布式锁Redlock

    引言 之前自己在用redis来实现分布式锁的时候都是基于单个Redis实例,也就是说Redis本身是有单点故障的,Redis的官方文档介绍了一种"自认为"合理的算法,Redlock ...

  4. 基于redis集群的分布式锁redlock

    Redis 作者为了解决因为主备切换.脑裂导致 Redis 单集群分布式锁不安全的问题,提出了 redlock 算法,下面是针对 文章 的翻译和一些自我理解. 一.安全性和可用性保证 用三个属性来建模 ...

  5. 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架。

    来自:why技术 又到了一周一次的分享时间啦,老规矩,还是先荒腔走板的聊聊生活. 有上面的图是读大学的时候,一次自行车骑行途中队友抓拍的我的照片.拍照的地方,名字叫做牛背山,一个名字很 low,实际很 ...

  6. 线上故障之-雪花算法重复、序列化、redis锁失效、double精准计算

    线上故障之-雪花算法重复.序列化.redis锁失效.double精准计算 雪花算法重复 问题发现 定位 影响范围 解决方案 扩展-雪花算法原理分析: 序列化 运营商 POP 裸机搭售自营套餐事故分析 ...

  7. 精尽 Redisson 源码分析 —— 可靠分布式锁 RedLock

    1. 概述 我们来看一个 Redis 主从结构下的示例,Redis 分布式锁是如何失效的: 1.客户端 A 从 Redis Master 获得到锁 anylock . 2.在 Redis Master ...

  8. 借助Redis锁,完美解决高并发秒杀问题

    欢迎关注方志朋的博客,回复"666"获面试宝典 场景:一家网上商城做商品限量秒杀. 1 单机环境下的锁 将商品的数量存到Redis中.每个用户抢购前都需要到Redis中查询商品数量 ...

  9. php 使用redis锁限制并发访问类

    1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...

最新文章

  1. topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
  2. 为什么我们总是喜欢选择差不多的价格
  3. delete不调用析构函数的两种情况
  4. LintCode 125. 背包问题 II(DP)
  5. ssh连接远程主机执行脚本的环境变量问题
  6. glassfish显示不了html文件,Glassfish websocket无法正常工作(示例代码)
  7. 你们一年大概可以存多少钱?
  8. ffmpeg系列-协议操作解析-AVIOContext,URLContext,URLProtocol,HTTPContext
  9. .net站点配置完后常见报错及解决措施
  10. C语言atoi()函数:将字符串转换成int(整数)
  11. 4.linux 命令行 光标移动技巧
  12. torchtext 中文语料加载
  13. opencontrail学习(一)
  14. python四分位数_四分位数计算以及使用pandas计算
  15. 一个写着玩的 bitcoin 客户端
  16. http://www.cvvision.cn/2888.html
  17. php远程下载到本地,PHP 下载远程文件到本地的简单示例
  18. 住院病历的病历打印纸要求多大?
  19. 鲁大师6月新机流畅榜:HarmonyOS跑分亮相
  20. app式成语_成语看图猜app

热门文章

  1. Python的作者及简介
  2. FutureTask多任务并发处理
  3. 二维数组快速排序sort
  4. 第一课 Docker践行DevOps理念-导学和安装
  5. php实现ajax登录验证用户名密码,php+jquery+ajax实现用户名验证
  6. java objectid_如何在java中创建mongoDB objectid
  7. 可观测可回溯 | Continuous Profiling 实践解析
  8. 我做分析师的十年感受 ( 三 )
  9. 详解自动编码器(AE)
  10. 用html4绘制海豚,CorelDRAW绘制一幅海豚嬉戏的海上风光效果图