Plantre Plantre
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

plantre

一个后端开发者
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机组成原理

  • 操作系统

  • 计算机网络

  • 设计模式

  • Java

  • Spring

  • SpringCloud

  • MySQL

  • Redis

  • 分布式

    • 理论等

      • 分布式锁
      • 从道法术器层面看分布式锁
      • 基于数据库的分布式锁
      • 基于Redis的分布式锁
      • 基于ZooKeeper的分布式锁
      • 从道法术器层面看分布式事务
      • 调用第三方怎么保证事务的四个特性
      • 最终一致和强一致性的区别
      • 本系统扣库存生成计费单,向第三方系统推送计费单,这两个场景分别用什么一致性
      • 单体改微服务,除了分布式锁,除了分布式事务,还要注意哪些问题
    • 分布式算法

    • 分布式事务

    • 分布式锁

    • SpringCloud

  • Zookeeper

  • Dubbo

  • Kafka

  • 数据结构

  • 算法

  • OJ

  • 从道家哲学看计算机?
  • 后端
  • 分布式
  • 理论等
plantre
2025-05-08

基于Redis的分布式锁

基于Redis的分布式锁实现方案解析

一、实现方式

  1. 基础命令:SETNX + EXPIRE
    通过SETNX(SET if Not eXists)尝试设置锁,成功后使用EXPIRE设置过期时间。
    • 优点:简单易实现。

    • 缺点:非原子操作,若SETNX后宕机可能导致死锁。

    • 示例:

    result = client.setnx(lock_name, 1)
    if result: client.expire(lock_name, timeout)
    
    1
    2
  2. 原子操作:SET key value NX PX
    使用Redis 2.6.12+的SET命令一步完成锁的设置与超时配置。
    • 优点:原子性保障,避免死锁。

    • 示例:

    client.set(lock_name, value, nx=True, px=timeout)
    
    1
  3. RedLock算法(多实例锁)
    向多个独立的Redis实例并行申请锁,半数以上成功即视为获取锁。
    • 优点:高可用性,容错性强。

    • 缺点:实现复杂,需处理时钟漂移问题。

    • 适用场景:Redis集群环境。

  4. Lua脚本封装
    通过Lua脚本将加锁、释放锁操作原子化,避免网络延迟导致的操作拆分风险。
    • 核心代码:

    -- 加锁脚本
    if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then
        redis.call('expire', KEYS[1], ARGV[2])
        return 1
    else
        return 0
    end
    -- 解锁脚本(需验证锁持有者)
    if redis.call('get', KEYS[1]) == ARGV[1] then
        return redis.call('del', KEYS[1])
    else
        return 0
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    • 优点:保证原子性,防止误删锁。


二、关键机制

  1. 锁超时与自动释放
    • 必要性:防止客户端宕机导致死锁。

    • 优化:设置合理的过期时间(通常为业务预估耗时的2-3倍)。

  2. 锁续命(Watchdog机制)
    • 原理:后台线程定期续期锁的过期时间(如Redisson默认每10秒续期一次)。

    • 适用场景:长事务处理(如订单履约)。

  3. 锁持有者验证
    • 实现:释放锁时需验证value的唯一性(如UUID),防止误删其他客户端的锁。


三、进阶技术

  1. 可重入锁
    • 实现:通过计数器记录锁的持有次数,支持同一线程多次加锁。

    • 示例:Redisson的RLock接口支持可重入性。

  2. 公平锁
    • 实现:基于ZooKeeper的临时顺序节点,按请求顺序分配锁。

    • 适用场景:需避免资源饥饿的敏感业务。

  3. 锁监控与告警
    • 指标:锁竞争频率、平均持有时间、异常释放次数。

    • 工具:Prometheus + Grafana监控Redis锁状态。


四、优缺点与选型建议

方案 优点 缺点 适用场景
SETNX+EXPIRE 简单易实现 非原子性,存在死锁风险 低频、非关键业务
SET NX PX 原子性操作,性能高 单点故障风险 高并发短事务(如秒杀)
RedLock 容错性强,支持集群 实现复杂,需多实例部署 金融等高可用场景
Redisson框架 支持可重入、自动续期,功能完善 依赖Java生态 企业级Java应用

五、最佳实践

  1. 避免锁粒度过大
    • 例如,库存扣减锁应细化到商品SKU级别。

  2. 降级策略
    • 加锁失败时,返回“稍后重试”提示或异步排队处理。

  3. 容灾兜底
    • 结合数据库事务或离线对账系统,弥补最终一致性的潜在漏洞。

  4. 框架推荐
    • Java:优先使用Redisson,内置锁续期、可重入等高级特性。

    • Python/Go:结合SET NX PX与Lua脚本实现基础锁。


六、典型问题与解决方案

  1. 锁提前释放
    • 原因:业务处理时间超过锁的过期时间。

    • 方案:启用Watchdog自动续期机制。

  2. 脑裂导致锁失效
    • 场景:Redis主从切换时,新主节点未同步锁信息。

    • 方案:使用RedLock算法或集群模式(Redis Cluster)。

  3. GC停顿导致锁超时
    • 现象:JVM Full GC暂停线程,导致锁未被续期。

    • 优化:缩短锁超时时间,增加续期频率。


总结 基于Redis的分布式锁需综合考虑性能、一致性与复杂度。对于大多数场景,SET NX PX结合Lua脚本已能满足需求;高可用场景可选用RedLock或Redisson框架。关键设计原则包括原子性保障、锁持有者验证、超时与续期机制,同时需通过监控和降级策略提升系统鲁棒性。

编辑 (opens new window)
上次更新: 2025/06/10, 09:18:05
基于数据库的分布式锁
基于ZooKeeper的分布式锁

← 基于数据库的分布式锁 基于ZooKeeper的分布式锁→

最近更新
01
集成loki
07-04
02
TCP的ESTABLISHED是什么意思
06-24
03
安装1panel
06-24
更多文章>
Theme by Vdoing | Copyright © 2025-2025 plantre | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式