分布式环境的分布式锁 - Redlock方案

简介: 【10月更文挑战第2天】Redlock方案是一种分布式锁实现,通过在多个独立的Redis实例上加锁来提高容错性和可靠性。客户端需从大多数节点成功加锁且总耗时小于锁的过期时间,才能视为加锁成功。然而,该方案受到分布式专家Martin的质疑,指出其在特定异常情况下(如网络延迟、进程暂停、时钟偏移)可能导致锁失效,影响系统的正确性。Martin建议采用fencing token方案,以确保分布式锁的正确性和安全性。

Redlock方案

前提:

  • 不需要再部署从库和哨兵实例,只部署主库
  • 主库要部署多个,官方推荐至少5个实例

整体流程:

  1. 客户端先获取 当前时间戳time1
  2. 客户端依次向这5个Redis实例发起加锁请求,而且每个请求会设置超时时间,注意这里的超时时间要远远的小于锁的有效时间,如果某一个实例加锁失败(包括网络超时、锁被其他人持有等各种异常情况),向下一个Redis实例申请加锁
  3. 如果客户端从 大于等于3个以上Redis实例加锁成功,则再次获取 当前时间戳time2 ,如果$time2-time1 < ddl$,其中ddl为锁的过期时间,认为客户端加锁成功,因为锁还未过期;否则,加锁失败
  4. 加锁成功,操作共享资源
  5. 加锁失败,向全部节点发起释放锁的请求

重点在于:

  • 客户端必须在多个独立的Redis实例上加锁

    本质是为了容错,因为如果部分实例宕机的话,剩余的实例加锁成功了,整个锁服务依旧可用

  • 必须保证大多数的节点都能加锁成功

    多个Redis实例构成了一个分布式系统,如果只存在故障节点,只要大多数节点正常,整个系统依旧是可以提供正确服务

  • 大多数节点加锁的总耗时,小于锁设置的过期时间

    操作的是多个节点,耗时会比单个实例的耗时多,而且网络层面也有延迟、丢包、超时等情况发生。所以如果大多数的节点加锁情况,但是加锁的累计耗时超过了锁的过期时间,有些实例的锁可能已经失效了,这个锁也没有意义

  • 释放锁,要向全部节点发起释放请求

    清理节点遗留的锁

对Relock的质疑

分布式专家Martin对Relock提出了质疑

分布式锁的目的是什么?

有两个目的:
一是效率,使用分布式锁的互斥功能,避免不必要地做同样地两次工作,例如一些昂贵地计算任务,而锁失效,并不会带来恶性的后果,例如发了2次邮件,问题不大
二是正确性,锁用来防止并发进程互相干扰,如果锁失效,会造成多个进程同时操作同一条数据,产生的后果是数据严重错误、永久性不一致、数据丢失等恶性问题。

如果是为了效率,使用单机版Redis就可以了,即使偶尔宕机/主从切换导致锁失效,都不会产生严重的后果。而Redlock依旧存在锁失效的问题,正确性也无法保证

锁在分布式系统中遇到的问题

分布式系统的异常场景

  • N:Network Delay 网络延迟
  • P:process Pause 进程暂停 GC
  • C:Clock Drift 时钟偏移

下面用一个进程暂停的例子来看Redlock的安全性问题

  1. 客户端1请求锁定节点A~E
  2. 客户端1拿到所以后,进入GC,时间维持久
  3. 所有Redis节点上的锁都过期了
  4. 客户端2获取到了A~E上的锁
  5. 客户端1的GC结束了,也认为自己成功获取到锁了
  6. 客户端2也同样认为 发生了冲突

假设时钟正确并不合理

当多个Redis节点时钟发生问题时,也会导致Redlock锁失效

  1. 客户端1获取节点A~C上的锁,但是因为网络问题,无法访问D和E
  2. 节点C上的时钟向前跳跃,导致锁到期
  3. 客户端2获取节点C~E上的锁,因为网络问题,无法访问A和B
  4. 客户端1和客户端2都觉得自己加锁成功

机器的时钟发生错误,主要有以下情况

  • 系统管理员手动修改了机器时钟
  • 机器时钟在同步NTP时间时,发生了大的跳跃

fencing token方案

Martin 提出一种被叫作 fencing token 的方案,保证分布式锁的正确性。
流程如下:

  1. 客户端在获取锁时,锁服务可以提供一个递增的 token
  2. 客户端拿着这个 token 去操作共享资源
  3. 共享资源可以根据 token 拒绝后来者的请求

这样是建立在异步模型上的,无论哪种情况发生,都可以保证安全性。
他还表示,一个好的分布式锁,无论 NPC 怎么发生,可以不在规定时间内给出结果,但并不会给出一个错误的结果。也就是只会影响到锁的性能,而不会影响它的正确性

目录
相关文章
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
105 2
基于Redis的高可用分布式锁——RedLock
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
14天前
|
NoSQL 算法 关系型数据库
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
本文详解分布式全局唯一ID及其5种实现方案,关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
55 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
22天前
|
存储 缓存 NoSQL
分布式架构下 Session 共享的方案
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求、系统架构和性能要求等因素,选择合适的 Session 共享方案。同时,还需要不断地进行优化和调整,以确保系统的稳定性和可靠性。
|
1月前
|
NoSQL Java Redis
Redlock分布式锁高并发下有什么问题
Redlock分布式锁在高并发场景下可能面临的问题主要包括:网络延迟、时钟偏移、单点故障、宕机重启问题、脑裂问题以及效率低等。接下来,我将使用Java代码示例来说明其中一些问题。
79 12
|
1月前
|
分布式计算 NoSQL Java
Hadoop-32 ZooKeeper 分布式锁问题 分布式锁Java实现 附带案例和实现思路代码
Hadoop-32 ZooKeeper 分布式锁问题 分布式锁Java实现 附带案例和实现思路代码
41 2
|
1月前
|
存储 SQL 消息中间件
Hadoop-26 ZooKeeper集群 3台云服务器 基础概念简介与环境的配置使用 架构组成 分布式协调框架 Leader Follower Observer
Hadoop-26 ZooKeeper集群 3台云服务器 基础概念简介与环境的配置使用 架构组成 分布式协调框架 Leader Follower Observer
45 0
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
这篇文章介绍了如何在SpringBoot项目中整合Redis,并探讨了缓存穿透、缓存雪崩和缓存击穿的问题以及解决方法。文章还提供了解决缓存击穿问题的加锁示例代码,包括存在问题和问题解决后的版本,并指出了本地锁在分布式情况下的局限性,引出了分布式锁的概念。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解、如何添加锁解决缓存击穿问题?分布式情况下如何添加分布式锁
|
2月前
|
Java
分布式-Zookeeper-分布式锁
分布式-Zookeeper-分布式锁

热门文章

最新文章