LiSheng's blog LiSheng's blog
首页
笔记
个人简历
随笔集
GitHub (opens new window)
首页
笔记
个人简历
随笔集
GitHub (opens new window)
  • golang

  • cplus

  • leetcode

  • 存储技术

  • 分布式系统

  • 计算机网络

  • Linux操作系统

  • Redis

    • 大纲
    • redis持久化策略
    • redis事务
    • redis分布式锁
      • redis高可用
      • redis主从同步
      • Redis是什么
      • Redis基本数据结构
      • Redis为什么这么快
      • 缓存击穿、缓存穿透、缓存雪崩
      • 热Key问题,如何解决热key问题
      • Redis 过期策略和内存淘汰策略
      • Redis 的持久化机制
      • Redis的高可用
      • 使用过Redis分布式锁
      • Redis的跳跃表
      • MySQL与Redis 如何保证双写一致性
      • Redis的Hash 冲突怎么办
      • 布隆过滤器
      • Redis 事务机制
    • 其他

    • 笔记
    • Redis
    lisheng
    2024-09-10
    目录

    redis分布式锁

    实现分布式锁的原理主要是通过确保同一时刻在分布式系统中的多个节点中,只有一个节点能获取到锁,其他节点必须等待锁被释放后才能获取。以下是实现 Redis 分布式锁的基本原理和核心步骤:

    # 1. 锁的唯一性

    • 唯一标识:每次获取锁时,都需要生成一个唯一标识符(通常是 UUID)。这个唯一标识符与锁关联,用来确保锁的持有者能够安全地释放锁,避免误删除其他客户端持有的锁。
    • 原子性操作:Redis 的 SETNX(Set if Not Exists)命令保证了在同一时间只有一个客户端能够成功设置某个键,也就是获取锁。

    # 2. 锁的过期时间

    • 防止死锁:当客户端获取锁后由于崩溃或网络问题无法释放锁,为防止死锁,必须为锁设置一个过期时间。过期时间到达后,锁会自动释放,使得其他客户端可以继续尝试获取锁。
    • 设置方法:可以通过 Redis 的 EXPIRE 命令或者在 SET 命令中使用 PX(毫秒)或 EX(秒)选项来设置过期时间。

    # 3. 锁的获取与释放

    • 获取锁:

      1. 客户端尝试使用 SETNX 命令创建锁,如果成功,则表示获取到了锁。
      2. 如果获取成功,再设置锁的过期时间,以防止因客户端崩溃导致锁无法释放。
      3. 如果未获取成功,则锁已经被其他客户端持有,此时客户端可以选择重试或等待一段时间后再次尝试获取锁。
    • 释放锁:

      1. 客户端执行完业务逻辑后,需要安全地释放锁。通常的做法是检查当前锁的持有者是否为自己(通过唯一标识符对比),只有在持有锁的客户端才能执行 DEL 命令释放锁。
      2. 释放锁的操作需要是原子性的,可以通过 Lua 脚本来确保操作的原子性。

    示例代码:

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

    # 4. 锁的安全性

    • 避免误删锁:客户端在释放锁之前,必须先检查锁的持有者是否是自己。通过对比锁的值(唯一标识符),可以避免误删其他客户端的锁。
    • 防止锁的提前释放:通过 Lua 脚本将 SETNX 和 EXPIRE 组合成一个原子操作,防止在客户端崩溃或网络分区的情况下,出现锁未设置过期时间的情况。

    # 5. 锁的续期机制

    • 长时间任务的锁续期:如果业务逻辑执行时间超过锁的过期时间,可以设计一个锁续期机制,在业务逻辑执行过程中不断续期锁,防止锁过期导致其他客户端误获取锁。
    • 定期续期:客户端可以在锁快要过期时,使用 EXPIRE 命令延长锁的过期时间。

    # 6. Redlock算法

    • 背景:在单节点的 Redis 上设置分布式锁虽然简单,但在实际生产环境中,为了保证高可用性,通常会有多个 Redis 实例。这就引出了 Redlock 算法。
    • 算法步骤:
      1. 客户端在 N 个 Redis 实例(如5个)上依次尝试获取同样的锁。
      2. 每次获取锁时都设置相同的唯一标识符和过期时间。
      3. 如果客户端能在超过半数(即 N/2 + 1)的实例上成功获取锁,视为获取锁成功。
      4. 如果锁获取失败,或者在尝试获取锁的过程中某个实例超时,应当立即释放所有实例上的锁。
    • 优点:Redlock 提供了更高的容错能力,即使个别实例失效,也能保证分布式锁的可用性和安全性。

    # 7. Redis实现分布式锁的挑战

    • 网络分区问题:在分布式系统中,网络分区是不可避免的。在出现网络分区的情况下,需要确保锁的安全性和一致性。
    • 时钟同步问题:由于不同服务器的时钟可能存在偏差,在实现分布式锁时,依赖时间的操作(如锁的过期时间)可能会带来不一致性,需要通过算法(如 Redlock)来保证。
    • 性能与延迟:获取分布式锁需要多个实例协调,如果实例之间的网络延迟较大,会影响锁的获取速度和系统的性能。

    # 8. 常见的分布式锁实现方式

    • 基于数据库:使用数据库的行锁或表锁实现分布式锁,但性能可能会受到影响。
    • 基于 Zookeeper:使用 Zookeeper 的临时节点和 Watcher 机制实现分布式锁,适合高可用要求较高的场景。
    • 基于 Redis:使用 Redis 实现分布式锁,性能较高,但需要注意 Redis 单点故障和数据一致性的问题。

    # 9. Redis分布式锁的适用场景

    • 订单系统中的库存扣减:确保同一时刻只有一个订单能够成功扣减库存,避免超卖。
    • 定时任务的调度:在分布式任务调度系统中,保证同一任务不会被多个节点同时执行。
    • 分布式系统中的资源访问:保证资源在多个节点之间的安全访问,防止数据冲突。

    通过理解这些原理,你可以更好地掌握 Redis 分布式锁的实现,并在实际项目中应用这些技术来解决并发控制问题。

    编辑 (opens new window)
    上次更新: 2024/09/13, 11:59:12
    redis事务
    redis高可用

    ← redis事务 redis高可用→

    最近更新
    01
    ceph分布式存储-对象存储(RGW)搭建
    10-27
    02
    ceph分布式存储-集群客户端连接
    10-27
    03
    ceph分布式存储-管理crushmap
    10-27
    更多文章>
    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式