Redis实现的分布式锁服务红锁(RedLock)

我们前面文章《分布式锁服务的思考》中已经提出来为什么要加锁,以及对什么资源加锁,大家最好先过去简单看一下。今天我们继续学习一下如何结合Redis实现一个分布式锁服务。我们先实现一个简单的分布式锁服务,然后分析单节点锁存在的问题,再由问题引入Redis的分布式锁服务红锁的设计。

Redis实现的分布式锁服务红锁(RedLock)

目录:

  1. redis简单介绍

  2. 简单的分布式锁服务

  3. 可靠的分布式锁服务

  4. 代码示例

1. Redis简单介绍

Redis本身是内存数据库,适合用来对热点数据、瞬时数据(expire)、近似统计数据做存储,不小心丢失了部分数据也不要紧。例如我们用来统计每个IP的访问频率,用来做限流或者防止爬虫,同时也记录IP和对应的登录用户ID,防止恶意接口检测。同时Redis具有一个特征:结合Lua脚本可以实现原子性操作,我们可以利用Redis的这个特点,来实现一个锁服务。

2.使用Redis实现一个不可靠的分布式锁服务

主要的指令:

SET resource random_value NX PX 3000

该指令对key = resource的资源加过期时间为3000ms的锁,如果该资源已经被加锁了,说明key存在,本次加锁失败。

需要注意的是:设置的value在本资源锁的请求中一定是不可重复的,因为在锁释放的过程中需要key和value都对应了才可以删除的,防止删除了其他客户端加的锁。例如:A获得了锁,并承诺3秒内释放锁。可结果A执行了大于3秒,此时A的锁是被Redis被动释放的,锁释放后B获得了该资源锁,A终于执行完毕,然后删除key执行锁释放,会把B的锁误删的。因此释放锁需要结合key和value才行。

释放锁的Lua脚本如下:

Redis实现的分布式锁服务红锁(RedLock)

我们使用Java代码结合上面的Lua脚本实现一个简单的锁,如下:

Redis实现的分布式锁服务红锁(RedLock)

头条代码没格式化,贴图吧

思考:

既然单节点存在单点故障,我们添加一个slave可以吗?不可以,因为redis的主备是异步复制。

  1. 客户端A在master上获得锁,之后master在没有同步到slave就崩溃了。

  2. slave提升为master,客户端B在新的master上获得了A已经获得的资源锁。

非分布式或集群的系统本身就没有可靠性可言,所以上面我们讨论的锁在非分布式系统中可以应用良好。下面带大家认识下Redis的分布式锁服务——红锁。

3.利用Redis实现可靠的分布式锁服务——红锁

Redis把分布式锁的算法称之为红锁,Redis + Lock = RedLock。红锁需要N个(>=3)Redis独立节点,这些节点相互之间不需要有信息交流,保持独立即可。红锁基本的思路是:客户端在每个Redis实例上获得锁(就是上面讲过的指令),只要大多数实例上成功获得锁就算加锁成功。红锁的算法已经有很多实现版本,JAVA对应的实现版本是Redisson,我们可以在业务中直接引入并使用。虽然不需要我们自己去实现算法,但是有必要了解一下红锁的算法,下面我们描述一下客户端获得锁的流程:

  1. 客户端首先记录当前时间,用于后面计算总耗时。

  2. 客户端使用相同的key和随机value,从所有的Redis节点上获得锁。客户端在每个实例上设置锁的过程中,需要设超时时间(5-50ms),不成功就换下一个实例继续设置锁,用来防止客户端阻塞在一个down掉都实例上。

  3. 客户端需要计算获得锁的总耗时。客户端从至少N/2 + 1个节点上成功获得锁,且总耗时小于锁过期时间才能成功获得锁。

  4. 客户端获得锁之后,该锁的有效期不再是最初的过期时间,因为客户端要从多个节点上获得锁,需要去掉这些过程耗时。

  5. 如果客户端最终获得锁失败,必须在所有节点上执行锁释放。

以上算法保证了:

  • 锁互斥性,同一时间只能有一个锁

  • 不会死锁,使用锁过期时间。

  • 多节点容错,只要大多数节点获取了锁就可以认为成功获取锁。

4.Redisson实现的分布式锁

Redisson是基于Netty、Redis、JDK实现的更上层的应用工具,它提供了分布式对象和服务。Redisson命令的发送可以支持同步方式,异步方式,Redisson可以支持多种Redis的实际部署方式,例如:单节点、集群、主备、热备、哨兵、云服务。可参考下面官方的架构图:

Redis实现的分布式锁服务红锁(RedLock)

我们使用Redisson的分布式锁服务,因为Redisson支持Redis的集群部署、热备部署、哨兵部署、主备部署多种方式,而今天我们重点不在Redis的部署,所以我们就简单部署3个独立的Redis节点就可以实验了。

Redis实现的分布式锁服务红锁(RedLock)

使用编码的方式获得Redisson实例

Redis实现的分布式锁服务红锁(RedLock)

通过3个实例,获得红锁

Redis实现的分布式锁服务红锁(RedLock)

加锁和释放锁

我们通过上面的代码片段,简单写一个工具类:

Redis实现的分布式锁服务红锁(RedLock)

贴图保格式

总结

  1. Redis的应用场景简介。这里大家先思考redis开发模式和规范,强调下,仅仅使用key->value是很恐怖的事情。

  2. 我们分析了单节点Redis的锁不可靠,引入了红锁算法。

  3. 带领大家认识了功能丰富的Redisson,我们仅介绍了红锁功能。

希望本文章能带给大家一点收获,能理解到锁的重要,保证业务一致性才是锁的使命。谢谢大家阅读,不足之处评论指出。


分享到:


相關文章: