当前位置: 首页 > news >正文

Redis 如何实现分布式锁,以及redis的适应场景分析

Redis 实现分布式锁的核心是利用 SET NX EX 命令(原子性地实现“不存在则设置+过期时间”),确保同一时刻只有一个客户端获得锁,再配合 Lua 脚本保证释放锁的原子性。

1. 核心原理:加锁(获取锁)

通过 SET key value NX EX expireTime 命令实现,该命令是原子操作,能避免“检查-设置”的竞态问题。

  • NX(Not Exist):仅当 key 不存在时才设置成功,确保只有一个客户端拿到锁。

  • EX(Expire):为 key 设置过期时间(如 5 秒),避免客户端崩溃后锁永久无法释放。

  • value:建议使用 唯一随机值(如 UUID),确保释放锁时只能删除自己加的锁,避免误删他人的锁。

      示例命令(Redis CLI):SET lock:order UUID-123 NX EX 5- 执行成功(拿到锁):返回 OK。- 执行失败(锁已存在):返回 nil。
    

2. 关键步骤:释放锁(避免误删)

释放锁需先判断“当前锁的 value 是否为自己的随机值”,再删除 key,这两步必须原子执行,否则会出现“客户端 A 删了客户端 B 的锁”的问题。

解决方案:用 Lua 脚本执行判断+删除,Redis 会将脚本作为整体原子执行。

Lua 脚本示例:
-- 1. 判断锁的 value 是否等于传入的随机值(确保是自己的锁)
-- 2. 若相等则删除锁,返回 1;否则返回 0
if redis.call("GET", KEYS[1]) == ARGV[1] thenreturn redis.call("DEL", KEYS[1])
elsereturn 0
endKEYS[1]:锁的 key(如 lock:order)
ARGV[1]:加锁时的随机值(如 UUID-123)

3. 进阶优化:解决“锁过期”问题

若客户端拿到锁后,业务执行时间超过锁的过期时间,锁会自动释放,可能导致多个客户端同时持有锁。

解决方案:为锁添加 “续约机制”(即“看门狗”):

  • 客户端拿到锁后,启动一个后台线程(如定时任务)。

  • 线程每隔 过期时间的 1/3(如锁过期 5 秒,则每隔 1.5 秒)检查一次:若当前客户端仍持有锁,则延长锁的过期时间至 5 秒。

  • 当业务执行完成或客户端崩溃,线程停止,锁不再续约,到期后自动释放。

4. 常见方案:基于 Redisson 简化实现

手动实现上述逻辑较复杂,实际项目中常用 Redis 客户端 Redisson(支持 Java、Python 等),它已封装好分布式锁的完整逻辑(加锁、续约、释放锁),开箱即用。

Java 示例(Redisson):
// 1. 获取 Redisson 客户端
RedissonClient redisson = Redisson.create(config);// 2. 获取分布式锁(key 为 lock:order)
RLock lock = redisson.getLock("lock:order");try {// 3. 加锁(默认 30 秒过期,自动启动看门狗续约)lock.lock();// 4. 执行核心业务(如创建订单)doBusiness();
} finally {// 5. 释放锁(自动判断是否为自己的锁,避免误删)lock.unlock();
}

5. redis使用场景

Redis 分布式锁适用于 并发量中等、对锁可靠性要求非极致严苛,但追求高性能与低延迟 的分布式场景,核心用于解决跨服务/跨节点的资源竞争问题,典型使用场景如下:

1. 防止接口重复请求/幂等性保障

当多个客户端(或服务)可能重复调用同一接口(如用户重复提交订单、重复支付)时,用 Redis 分布式锁确保“同一业务标识下,仅一次请求能执行核心逻辑”。

  • 示例:用户提交订单时,以“用户ID+订单唯一标识”为锁 key,获取锁成功才执行“创建订单”逻辑;未获取到锁则直接返回“请求处理中”或“订单已存在”,避免生成重复订单。

2. 控制分布式任务的并发执行

当多个服务节点同时监听并执行同一类任务(如定时任务、消息消费)时,用 Redis 分布式锁避免“同一任务被多节点重复执行”,确保任务唯一执行。

  • 示例:分布式定时任务(如每日凌晨同步用户数据),以“任务名称+日期”为锁 key,仅抢到锁的服务节点执行同步逻辑,其他节点跳过,避免重复同步导致数据冗余或冲突。

3. 限制共享资源的并发访问

当多个服务需要操作同一共享资源(如修改数据库同一条记录、操作分布式缓存中的同一 key、调用第三方有限资源接口)时,用 Redis 分布式锁控制“同一时间仅一个服务能操作资源”。

  • 示例1:多服务修改数据库中“商品库存”,以“商品ID”为锁 key,抢到锁的服务才能执行“库存减1”操作,避免超卖。

  • 示例2:调用第三方支付接口(有每秒调用次数限制),以“接口名称”为锁 key,控制同一时间仅一个请求调用接口,避免触发限流。

4. 分布式系统中的“临界区”保护

在分布式架构中,若存在“多节点需串行执行的代码块”(即临界区,如初始化全局配置、更新分布式计数器),用 Redis 分布式锁确保“临界区逻辑仅一个节点执行”,避免数据不一致。

  • 示例:分布式系统启动时初始化全局配置到缓存,以“config:init”为锁 key,仅第一个启动的节点执行初始化,其他节点直接读取缓存,避免重复初始化覆盖数据。

5. 秒杀/抢购场景的并发控制

秒杀、抢购场景下,大量请求同时争抢有限商品,需用 Redis 分布式锁结合其高性能特性,控制“同一商品的下单逻辑串行执行”,配合库存预扣减,缓解数据库压力并避免超卖。

注意:该场景需优化锁粒度(如按商品ID分锁,而非全局锁),并结合 Redis 原子操作(如 DECR 预扣减库存)提升性能,避免锁成为瓶颈。

不适合的场景

需明确 Redis 分布式锁的局限性,以下场景不建议使用:

  • 金融级强一致性场景(如银行转账、账务核算):需绝对避免“锁丢失”“并发持有锁”,建议用 ZooKeeper/etcd 分布式锁。

  • 业务执行时间远超锁过期时间的场景:若业务逻辑(如大数据计算)耗时数分钟,“看门狗”续约机制仍有失效风险,需重新评估锁方案。

总结

Redis 分布式锁的核心优势是 高性能、低延迟、部署成本低,因此在互联网业务中(如电商、社交、内容平台)的“非金融级并发控制”场景中应用广泛,是平衡“可靠性”与“性能”的优选方案。

http://www.dtcms.com/a/361962.html

相关文章:

  • 【跨平台编译】【树莓派】在x86上编译树莓派上运行的CC++代码,搭建树莓派4B的跨平台编译环境
  • ccache编译加速配置
  • Meteor主题友链页面自研
  • Qt 的信号signal的参数是否会在内部被拷贝?
  • Vue3 中 Proxy 在组件封装中的妙用
  • 【网络安全入门基础教程】网络安全零基础学习方向及需要掌握的技能
  • Electron 应用生命周期管理:app 模块核心 API
  • 【 HarmonyOS 】错误描述:The certificate has expired! 鸿蒙证书过期如何解决?
  • 光学神经网络与人工智能应用
  • 网络流量分析——熟悉Wireshark
  • 【洛谷】【模板】栈、有效的括号、验证栈序列、后缀表达式、(stack相关算法题)
  • 腾讯位置商业授权微信小程序获取城市列表
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(二十三)控件中常用文本格式
  • 玩转OurBMC第二十一期:前端页面仪表盘的设计与使用实践
  • js 海康视频插件的具体步骤
  • QMainWindow使用QTabWidget添加多个QWidget
  • Simulink库文件-一种低通滤波模块搭建方法
  • 优化正则表达式性能:预编译与模式匹配的最佳实践
  • 均值滤波和中值滤波的简介、C语言实现和实测
  • 边缘计算设备 RK3576芯片
  • CGroup 资源控制组 + Docker 网络模式
  • NLP大语言模型数据准备
  • NLP技术突破:浅层与深层语义分析全解析
  • 嵌入式学习(day37) 数据库 Sqlite相关命令函数
  • Salesloft OAuth漏洞影响范围大幅增加,波及所有集成应用
  • 可编辑115页PPT | 某纸制品制造企业数字化转型战略规划项目建议书
  • 闭包的简单讲解
  • 三、数据结构
  • VMware安装
  • 基于docker-compose搭建EFK(Elasticsearch+fluentd+kibana)的日志平台