首页 > 数据库 >Redis分布式锁最牛逼的实现 Redlock

Redis分布式锁最牛逼的实现 Redlock

时间:2023-03-27 23:32:27浏览次数:41  
标签:Redlock redis Redis value 获取 实例 节点 分布式

普通实现

说道Redis分布式锁大部分人都会想到:setnx+lua,或者知道set key value px milliseconds nx。后一种方式的核心实现命令如下:

- 获取锁(unique_value可以是UUID等)
SET resource_name unique_value NX PX 30000

- 释放锁(lua脚本中,一定要比较value,防止误解锁)
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

这种实现方式有3大要点(也是面试概率非常高的地方):

set命令要用set key value px milliseconds nx; value要具有唯一性; 释放锁时要验证value值,不能误解锁; 事实上这类琐最大的缺点就是它加锁时只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:

在Redis的master节点上拿到了锁; 但是这个加锁的key还没有同步到slave节点; master故障,发生故障转移,slave节点升级为master节点; 导致锁丢失。 正因为如此,Redis作者antirez基于分布式环境下提出了一种更高级的分布式锁的实现方式:Redlock。笔者认为,Redlock也是Redis所有分布式锁实现方式中唯一能让面试官高潮的方式。

Redlock实现

antirez提出的redlock算法大概是这样的:

在Redis的分布式环境中,我们假设有N个Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。我们确保将在N个实例上使用与在Redis单实例下相同方法获取和释放锁。现在我们假设有5个Redis master节点,同时我们需要在5台服务器上面运行这些Redis实例,这样保证他们不会同时都宕掉。

为了取到锁,客户端应该执行以下操作:

获取当前Unix时间,以毫秒为单位。 依次尝试从5个实例,使用相同的key和具有唯一性的value(例如UUID)获取锁。当向Redis请求获取锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒,则超时时间应该在5-50毫秒之间。这样可以避免服务器端Redis已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试去另外一个Redis实例请求获取锁。 客户端使用当前时间减去开始获取锁时间(步骤1记录的时间)就得到获取锁使用的时间。当且仅当从大多数(N/2+1,这里是3个节点)的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算获取成功。 如果取到了锁,key的真正有效时间等于有效时间减去获取锁所使用的时间(步骤3计算的结果)。 如果因为某些原因,获取锁失败(没有在至少N/2+1个Redis实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的Redis实例上进行解锁(即便某些Redis实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁)。

Redlock源码

redisson已经有对redlock算法封装,接下来对其用法进行简单介绍,并对核心源码进行分析(假设5个redis实例)。 POM依赖

<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.3.2</version>
</dependency>

用法 首先,我们来看一下redission封装的redlock算法实现的分布式锁用法,非常简单,跟重入锁(ReentrantLock)有点类似:

Config config1 = new Config();
config1.useSingleServer().setAddress("redis://192.168.0.1:5378")
        .setPassword("a123456").setDatabase(0);
RedissonClient redissonClient1 = Redisson.create(config1);

Config config2 = new Config();
config2.useSingleServer().setAddress("redis://192.168.0.1:5379")
        .setPassword("a123456").setDatabase(0);
RedissonClient redissonClient2 = Redisson.create(config2);

Config config3 = new Config();
config3.useSingleServer().setAddress("redis://192.168.0.1:5380")
        .setPassword("a123456").setDatabase(0);
RedissonClient redissonClient3 = Redisson.create(config3);

String resourceName = "REDLOCK_KEY";

RLock lock1 = redissonClient1.getLock(resourceName);
RLock lock2 = redissonClient2.getLock(resourceName);
RLock lock3 = redissonClient3.getLock(resourceName);
// 向3个redis实例尝试加锁
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
boolean isLock;
try {
    // isLock = redLock.tryLock();
    // 500ms拿不到锁, 就认为获取锁失败。10000ms即10s是锁失效时间。
    isLock = redLock.tryLock(500, 10000, TimeUnit.MILLISECONDS);
    System.out.println("isLock = "+isLock);
    if (isLock) {
        //TODO if get lock success, do something;
    }
} catch (Exception e) {
} finally {
    // 无论如何, 最后都要解锁
    redLock.unlock();
}

链接:https://www.jianshu.com/p/7e47a4503b87。

标签:Redlock,redis,Redis,value,获取,实例,节点,分布式
From: https://blog.51cto.com/u_15993308/6153345

相关文章

  • Redis 有序集合(sorted set)
    Redis有序集合(sortedset)Redis有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通......
  • redisObject
    结构/**Redis对象*/typedefstructredisObject{//类型4bitsunsignedtype:4;//编码方式4bitsunsignedencoding:4;//LRU时间(相......
  • ASP.NET Core使用filter和redis实现接口防重
    背景日常开发中,经常需要对一些响应不是很快的关键业务接口增加防重功能,即短时间内收到的多个相同的请求,只处理一个,其余不处理,避免产生脏数据。这和幂等性(idempotency)稍微......
  • pytest--xdist分布式运行
    前言当测试用例数量上去以后,执行一遍所有测试用例,那么执行速度就会比较慢,除了多线程来提高效率外,pytest也提供pytest-xdist插件来做分布式执行,从而减少测试时间,它属于进程......
  • MATLAB代码:基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究
    MATLAB代码:基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究关键词:分布式调度ADMM算法交替方向乘子法碳排放最优潮流 仿真平台:MATLAB+CPLEXGUROBI平台......
  • 分布式微电网能源交易算法matlab源代码 孤岛微电网之间的能源交易问题,提出了一种分布
    分布式微电网能源交易算法matlab源代码,代码按照高水平文章复现,保证正确孤岛微电网之间的能源交易问题,提出了一种分布式算法。这个问题由几个通过任意拓扑交换能量流的岛......
  • Redis 列表(List)
    Redis列表(List)Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含232-1个元素(4294967295,......
  • Redis 哈希(Hash)
    Redis哈希(Hash)Redishash是一个string类型的field(字段)和value(值)的映射表,hash特别适合用于存储对象。Redis中每个hash可以存储232-1键值对(40多亿)。实......
  • C# StackExchange.Redis 用法总结
    阅读目录安装 StackExchange.Redis引用及初始化String(字符串)List(列表)Hash(哈希)发布订阅事务Batch批量操作Lock(分布式锁)StackExchange.Redis封装安装 St......
  • redis hash类型操作
    Redis-Hash前言hash在很多编程语言中都有着很广泛的应用,而在Redis中也是如此,在redis中,哈希类型是指Redis键值对中的值本身又是一个键值对结构,形如value=[{field1,value1},......