前言

RedLock 红锁,是分布式锁中必须要了解的一个概念。

所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个基本的了解。然后再看 Redisson 中是如何实现 RedLock 的。

在文章开头先说明 Redisson RedLock 建议不要使用!!!

在文章开头先说明 Redisson RedLock 建议不要使用!!!

在文章开头先说明 Redisson RedLock 建议不要使用!!!

重要的事情重复三遍!

什么是 RedLock?

RedLock,这块可以从网上搜到很多资料,本文也简单介绍下,当做扫盲。

单实例加锁

SET resource_name my_random_value NX PX 30000

对于单实例 Redis 只需要使用这个命令即可。

  • NX:仅在不存在 key 的时候才能被执行成功;
  • PX:失效时间,传入 30000,就是 30s 后自动释放锁;
  • my_random_value:就是随机值,可以是线程号之类的。主要是为了更安全的释放锁,释放锁的时候使用脚本告诉 Redis: 只有 key 存在并且存储的值和我指定的值一样才能删除成功

可以通过以下 Lua 脚本实现锁释放:

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

为什么要设置随机值?

主要是为了防止锁被其他客户端删除。有这么一种情况:

  1. 客户端 A 获得了锁,还没有执行结束,但是锁超时自动释放了;
  2. 客户端 B 此时过来,是可以获得锁的,加锁成功;
  3. 此时,客户端 A 执行结束了,要去释放锁,如果不对比随机值,就会把客户端 B 的锁给释放了。

当然前面看过 Redisson 的处理,这个 my_random_value 存放的是 UUID:ThreadId 组合成的一个类似 931573de-903e-42fd-baa7-428ebb7eda80:1 的字符串。

当锁遇到故障转移

单实例肯定不是很可靠吧?加锁成功之后,结果 Redis 服务宕机了,这不就凉凉~

这时候会提出来将 Redis 主从部署。即使是主从,也是存在巧合的!

主从结构中存在明显的竞态:

  1. 客户端 A 从 master 获取到锁
  2. 在 master 将锁同步到 slave 之前,master 宕掉了。
  3. slave 节点被晋级为 master 节点
  4. 客户端 B 取得了同一个资源被客户端 A 已经获取到的另外一个锁。安全失效!

有时候程序就是这么巧,比如说正好一个节点挂掉的时候,多个客户端同时取到了锁。如果你可以接受这种小概率错误,那用这个基于复制的方案就完全没有问题。

那我使用集群呢?

如果还记得前面的内容,应该是知道对集群进行加锁的时候,其实是通过 CRC16 的 hash 函数来对 key 进行取模,将结果路由到预先分配过 slot 的相应节点上。

发现其实还是发到单个节点上的

RedLock 概念

这时候 Redis 作者提出了 RedLock 的概念

总结一下就是对集群的每个节点进行加锁,如果大多数(N/2+1)加锁成功了,则认为获取锁成功。

RedLock 的问题

看着 RedLock 好像是解决问题了:

  1. 客户端 A 锁住了集群的大多数(一半以上);
  2. 客户端 B 也要锁住大多数;
  3. 这里肯定会冲突,所以 客户端 B 加锁失败。

那实际解决问题了么?

推荐大家阅读两篇文章:

最终,两方各持己见,没有得出结论。

鉴于本文主要是分析 Redisson 的 RedLock,就不做额外赘述,感兴趣的小伙伴可以自己阅读。

Redisson 中 RedLock 源码

这里会简要分析一下 Redisson 中 RedLock 的源码,然后会介绍为什么文章开头不建议大家使用 Redisson 的 RedLock。

使用方式

乍一看,感觉和联锁 MultiLock 的使用方式很像啊!

实际上就是很像,RedissonRedLock 完全是 RedissonMultiLock 的子类嘛!

只不过是重写 failedLocksLimit 方法。

在 MultiLock 中,要所有的锁都锁成功才可以。

在 RedLock 中,要一半以上的锁成功。

剩余部分源码都和 MultiLock 一样,就不在重复描述了。

Redisson 中 RedLock 的问题

1、加锁 key 的问题

阅读源码之前,有一个很大的疑问,我加锁 lock1、lock2、lock3,但是 RedissonRedLock 是如何保证这三个 key 是在归属于 Redis 集群中不同的 master 呢?

因为按照 RedLock 的理论,是需要在半数以上的 master 节点加锁成功

阅读完源码之后,发现 RedissonRedLock 完全是 RedissonMultiLock 的子类,只是重写了 failedLocksLimit 方法,保证半数以上加锁成功即可。

所以这三个 key,是需要用户来保证分散在不同的节点上的。

https://github.com/redisson/redisson/issues/2436

在 Redisson 的 issues 也有同样的小伙伴提出这个问题,相关开发者给出的回复是用户来保证 key 分散在不同的 master 上。

https://github.com/redisson/redisson/issues/2127

更有小伙伴提出使用 5 个客户端。

那我使用 5 个单节点的客户端,然后再使用红锁,听着好像是可以的,并且 RedissonRedLock 可以这样使用。

但是那和 Redis 集群还有啥关系啊!

所以依然没有解决我的问题,还是需要用户自己来“手工定位锁”。

手工定位锁,这个…… 我考虑了下,还是不用 RedLock 吧!

当然 DarrenJiang1990 同学应该是怀着打破砂锅问到底的心情,又来了一篇 issue。

https://github.com/redisson/redisson/issues/2437

意思就是:不要关闭我的 issues,在 #2436 中说可以“手工定位锁”,但是我要怎么手工定位锁。

后来这个 issue 在 10 月才回复。

2、RedissonRedLock 被弃用

是的,没有看错,现在 RedissonRedLock 已经被启用了。

如果是看的英文文档,就会发现:

而中文文档,应该是没有及时更新。

来看看更新记录:

再找一找 issue:

https://github.com/redisson/redisson/issues/2669

Redisson 的开发者认为 Redis 的红锁也存在争议(前文介绍的那个争议),但是为了保证可用性,RLock 对象执行的每个 Redis 命令执行都通过 Redis 3.0 中引入的 WAIT 命令进行同步。

WAIT 命令会阻塞当前客户端,直到所有以前的写命令都成功的传输并被指定数量的副本确认。如果达到以毫秒为单位指定的超时,则即使尚未达到指定数量的副本,该命令也会返回。

WAIT 命令同步复制也并不能保证强一致性,不过在主节点宕机之后,只不过会尽可能的选择最佳的副本(slaves)

源码在这一部分。

看源码,同时发送了一个 WAIT 1 1000 到 Redis。

结论

Redisson RedLock 是基于联锁 MultiLock 实现的,但是使用过程中需要自己判断 key 落在哪个节点上,对使用者不是很友好。

Redisson RedLock 已经被弃用,直接使用普通的加锁即可,会基于 wait 机制将锁同步到从节点,但是也并不能保证一致性。仅仅是最大限度的保证一致性。

相关推荐

Redisson 分布式锁源码 09:RedLock 红锁的故事的更多相关文章

  1. Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch

    前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...

  2. Redisson 分布式锁源码 02:看门狗

    前言 说起 Redisson,比较耳熟能详的就是这个看门狗(Watchdog)机制. 本文就一起看看加锁成功之后的看门狗(Watchdog)是如何实现的? 加锁成功 在前一篇文章中介绍了可重入锁加锁的 ...

  3. Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析

    原文:Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析 一.RedissonLock#lock 源码分析 1.根据锁key计算出 slot,一个slot对 ...

  4. RedissonLock分布式锁源码分析

    最近碰到的一个问题,Java代码中写了一个定时器,分布式部署的时候,多台同时执行的话就会出现重复的数据,为了避免这种情况,之前是通过在配置文件里写上可以执行这段代码的IP,代码中判断如果跟这个IP相等 ...

  5. ReentrantLock之非公平锁源码分析

    本文分析的ReentrantLock所对应的Java版本为JDK8. 在阅读本文前,读者应该知道什么是CAS.自旋. 由于ReentrantLock的公平锁和非公平锁中有许多共同代码,本文只会对这两种 ...

  6. Java关于ReentrantLock获取锁和释放锁源码跟踪

    通过对ReentrantLock获取锁和释放锁源码跟踪主要想进一步深入学习AQS. 备注:AQS中的waitStatus状态码含义:

  7. ReentrantLock 的公平锁源码分析

    ReentrantLock 源码分析   以公平锁源码解析为例: 1:数据结构: 维护Sync 对象的引用:   private final Sync sync; Sync对象继承 AQS,  Syn ...

  8. v79.01 鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上) | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(用户态锁篇) | 如何使用快锁Futex(上) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...

  9. v80.01 鸿蒙内核源码分析(内核态锁篇) | 如何实现快锁Futex(下) | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(内核态锁篇) | 如何实现快锁Futex(下) 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) ...

随机推荐

  1. Linux xargs命令-(转载)

    xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具.它把一个数据流分割为一些足够小的块,以方便过滤器和命令进行处理.通常情况下,xargs从管道或者stdin中读取数据,但是它也能够从 ...

  2. 快成物流科技 x mPaaS | 小程序容器加持下的技术架构“提质增效”

      导言 从 2017 年开始,GMTC"移动技术大会"就更名为"大前端技术大会".发展至今,混合开发.原生开发.前端开发等概念正在深度融合,组成"大 ...

  3. Redis()- 布隆过滤器

    一.布隆过滤器 布隆过滤器:一种数据结构.由二进制数组(很长的二进制向量)组成的.布隆过滤器可以用于检索一个元素是否在一个集合中.它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识 ...

  4. rocketmq常见问题及使用 新手篇

    一 部署阶段 1.启动命令 nameServer启动:nohup sh bin/mqnamesrv  -n ip地址:9876 & broker启动:nohup sh bin/mqbroker ...

  5. python发送丁丁消息

    import requests import time import hashlib import hmac import base64 import re def SendMessage(messa ...

  6. 摄像头ISP系统原理(中)

    摄像头ISP系统原理(中) AF(FOCUS)----自动对焦 根据光学知识,景物在传感器上成像最清晰时处于合焦平面上.通过更改 LENS 的位置,使得景物在传感器上清晰的成像,是 ISP FOCUS ...

  7. NVIDIA GPU的神经网络自动调度

    NVIDIA GPU的神经网络自动调度 针对特定设备和工作负载的自动调整对于获得最佳性能至关重要.这是一个关于如何使用自动调度器为NVIDIA GPU调整整个神经网络的资料. 为了自动调整一个神经网络 ...

  8. NVIDIA GPUs上深度学习推荐模型的优化

    NVIDIA GPUs上深度学习推荐模型的优化 Optimizing the Deep Learning Recommendation Model on NVIDIA GPUs 推荐系统帮助人在成倍增 ...

  9. HAL库与Cubemx系列|Systick-系统滴答定时器详解

    Systick是什么? 关于Systick,在Context-M3权威指南中如此描述: SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15).在以前,大多操作系统需要一 ...

  10. jmeter设置成中文显示

    meter默认语言设置: 1.临时设置: 进入options -- Choose Language -- 选择中文简体,设置后语言切换成中文,重启失效 2.永久设置:进入jmeter目录下的bin目录 ...