11. 如何使用 Redis 快速实现分布式锁

2023-08-02  本文已影响0人  木叶苍蓝

如何理解分布式锁

Redis 可以通过 set key 方式来实现分布式锁
实际开发中还要考虑如何确保超时情况下的串行,如何合理的释放锁等
本文要讲的是一个完备的分布式锁应该具备哪些特性
以及如何使用 Redis 来一步步优化实现

分布式锁需要具有哪些特点

20230802165036.jpg

使用 setnx 实现分布式锁

使用 setnx 实现分布式锁的方案:以该锁为 key 设置一个随机的值

如果需要阻塞当前进程,不断尝试 setnx 操作

if (setnx(key, value) == 1) {
  try {
    // 业务处理
  } finally {}
    // 释放锁
    del(key)
  }
}

使用 Java 中的 try-catch-finally 来完成锁的释放
使用这种方式来实现分布式锁的问题:不支持超时释放锁
如果进程在加锁后宕机,则会导致锁无法删除,其他进程无法获得锁

使用 setnx 和 expire 实现

if (setnx(key, value) == 1) {
  expire(key, expireTime)
  try {
    // 业务处理
  } finally {
    // 释放锁
    del(key)
  }
}

Redis 在设置一个 key 时,支持设置过期时间
可以在缓存中实现锁的超时释放,解决死锁问题
在 Redis 中,setnx 和 expire 这两个命令不具备原子性

在 Redis 2.8 版本中,扩展了 set 命令
支持 set 和 expire 指令组合使用
解决了加锁过程中失败的问题

SET key value expireTime nx

nx 表示仅在键不存在时设置
可以在同一时间内完成设置值和设置过期时间这两个操作
防止设置过期时间异常导致的死锁

set 扩展命令还存在问题吗?

在加锁和释放锁之间的业务逻辑执行的太长
以至于超出了锁的超时限制
缓存将对应的 key 删除,其他线程可以获取锁
出现对加锁资源的并发操作

案例:

如何避免上述问题?

分布式锁的高可用

在生产环境中,为了保证高可用,避免单点故障,通常会使用 Redis 集群

集群下分布式锁存在哪些问题

集群环境下,Redis 通过主从复制来实现数据同步,Redis 的主从复制(Replication)是异步的
所以单节点下可用的方案在集群的环境中可能会出现问题
在故障转移(Failover)过程中丧失锁的安全性
假设 Master 节点获取到锁后在未完成数据同步的情况下,发生节点崩溃
此时在其他节点依然可以获取到锁,出现多个客户端同时获取到锁的情况

模拟这个场景,按照下面的顺序执行:

关于集群下如何实现分布式锁 Redis 的作者提出了 Redlock 算法

Redlock 算法的流程

Redlock 算法是在单 Redis 节点基础上引入的高可用模式
Redlock 基于 N 个完全独立的 Redis 节点
一般是大于 3 的奇数个(通常情况下 N 可以设置为 5)
可以基于保证集群内各个节点不会同时宕机

假设当前集群有 5 个节点,运行 Redlock 算法的客户端依次执行下面各个步骤,来完成获取锁的操作:

在 Redis 官方推荐的 Java 客户端 Redisson 中,内置了对 RedLock 的实现
在实际业务中,一般使用基于单点的 Redis 实现分布式锁,出现数据不一致,通过人工手段去回补。

上一篇 下一篇

猜你喜欢

热点阅读