news 2026/4/20 20:24:30

基于 Redis 的分布式锁:原理剖析与 Spring Boot 实战(含看门狗续期)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Redis 的分布式锁:原理剖析与 Spring Boot 实战(含看门狗续期)

一、什么是分布式锁?

在单机应用中,我们常用synchronizedReentrantLock解决多线程并发问题,但这些锁的作用域局限于单个 JVM 进程。

当系统从单体架构演进为分布式集群时,多个服务实例、多个进程会并发操作共享资源(如库存、订单),此时本地锁已无法保证数据一致性,分布式锁应运而生。

分布式锁的核心目标:

  1. 互斥性:同一时刻只有一个客户端能持有锁
  2. 防死锁:锁必须能被释放,避免客户端崩溃导致锁永久占用
  3. 解铃还须系铃人:只能由加锁者自己释放锁,防止误删他人锁
  4. 高可用:锁服务本身不能成为单点故障

二、基于 Redis 的分布式锁核心原理

Redis 因其高性能、原子操作特性,成为实现分布式锁的主流选择,核心依赖以下几个关键能力:

1. 加锁:SET key value NX EX seconds原子指令

  • NX:仅当 key 不存在时才设置,保证互斥性
  • EX seconds:设置 key 的过期时间,避免客户端崩溃导致死锁
  • value:设置为客户端唯一 ID(如 UUID),用于后续判断锁的归属

2. 解锁:Lua 脚本原子删除

直接用DEL key解锁存在风险:若锁已过期,当前客户端可能误删其他客户端的锁。因此需要通过 Lua 脚本保证 “判断锁归属 + 删除锁” 的原子性:

-- 只有锁属于当前客户端,才执行删除 if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end

3. 看门狗机制:解决业务超时锁释放问题

上面的时间轴,帮助我们理解不加看门狗的时候,如果业务执行时间超过锁的过期时间,锁会被自动释放,导致并发安全问题。

看门狗机制则会在业务执行期间,周期性(通常为锁过期时间的 1/3)续期锁的过期时间,直到业务执行完成:

时间轴(秒) → 0 5 10 15 事务A(业务): ├──────────────────────┤ (执行完成) 锁A(分布式锁):├──续期→├──续期→├──续期→┤ (始终有效) 事务B(其他业务): (全程拿不到锁,阻塞等待)

三、Spring Boot + Jedis 4.x 实战实现

理解了上述原理,接下来请跟我一起实现吧!

1. 环境准备:依赖引入redis.clients:jedis:4.4.3

2.Jedis 连接池配置(适配 Jedis 4.x)

@Configuration public class JedisPoolConfig { @Value("${spring.redis.host:localhost}") private String host; @Value("${spring.redis.port:6379}") private int port; @Value("${spring.redis.password:}") private String password; @Value("${spring.redis.timeout:2000}") private int timeout; @Bean public JedisPooled jedisPooled() { // 先定义 host+port HostAndPort hostAndPort = new HostAndPort(host, port); // 构建客户端配置(超时、密码) DefaultJedisClientConfig.Builder configBuilder = DefaultJedisClientConfig.builder() .connectionTimeoutMillis(timeout) .socketTimeoutMillis(timeout); if (password != null && !password.isBlank()) { configBuilder.password(password); } DefaultJedisClientConfig clientConfig = configBuilder.build(); // 构建连接池配置(最大连接数、空闲连接) GenericObjectPoolConfig<Connection> poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(20); poolConfig.setMaxIdle(10); poolConfig.setMinIdle(5); // Jedis 4.x 唯一正确的构造方法 return new JedisPooled(poolConfig, hostAndPort, clientConfig); } }

3. 分布式锁核心

3.1 加锁

// 加锁 public RedisLock lock(String lockKey, int expireSeconds) { this.lockKey = lockKey; this.expireSeconds = expireSeconds; this.requestId = UUID.randomUUID().toString(); this.isLocked = false; SetParams params = new SetParams(); params.nx().ex(expireSeconds); String result = jedis.set(lockKey, requestId, params); if (!LOCK_SUCCESS.equals(result)) { return null; } this.isLocked = true; startWatchDog(); return this; }

3.2 解锁

直接DEL会导致误删锁,必须先判断锁归属再删除。(用lua脚本)

// 解锁 public void unlock() { if (!isLocked) return; isLocked = false; stopWatchDog(); String lua = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end"; jedis.eval(lua, Collections.singletonList(lockKey), Collections.singletonList(requestId)); } private void stopWatchDog() { if (scheduler != null) scheduler.shutdown(); } @Override public void close() { unlock(); }

3.3 看门狗机制

注意在业务结束或异常时要停止续期线程,避免资源泄漏

// 看门狗自动续期 private void startWatchDog() { scheduler = Executors.newSingleThreadScheduledExecutor(); long delay = expireSeconds * 1000L / 3; scheduler.scheduleAtFixedRate(() -> { if (!isLocked) { stopWatchDog(); return; } try { String currentVal = jedis.get(lockKey); if (requestId.equals(currentVal)) { jedis.expire(lockKey, expireSeconds); System.out.println("[看门狗] 续期成功: " + lockKey); } } catch (Exception e) { stopWatchDog(); } }, delay, delay, TimeUnit.MILLISECONDS); }

测试结果:

并发锁测试:

同一时间只有一个线程能抢到锁,其他线程全部抢锁失败,验证了互斥性。

看门狗续期测试

执行业务时间超过锁过期时间(如锁 5 秒过期,业务执行 15 秒),可以看到看门狗周期性打印续期日志,锁不会被提前释放。

总结

redis分布式锁要保证原子性 + 过期时间 + 唯一标识 + 锁续命

1)通过SET NX EX指令实现原子加锁并设置过期时间;

2)使用Lua脚本保证解锁的原子性,防止误删;

3)引入看门狗机制自动续期,解决业务执行超时问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 20:16:53

Turbo ACC网络加速技术解析与实践指南

Turbo ACC网络加速技术解析与实践指南 【免费下载链接】turboacc 一个适用于官方openwrt(22.03/23.05/24.10) firewall4的turboacc 项目地址: https://gitcode.com/gh_mirrors/tu/turboacc Turbo ACC是专为OpenWrt官方版本&#xff08;22.03/23.05/24.10&#xff09;fir…

作者头像 李华
网站建设 2026/4/20 20:14:37

基于量化感知训练的YOLOv5定点化部署:从模型训练到边缘端落地全指南

摘要 在边缘计算场景下,YOLOv5模型虽然精度高但参数量大、计算密集,难以直接部署在算力有限的嵌入式设备上。本文提出一套完整的基于量化感知训练(Quantization-Aware Training, QAT)的YOLOv5定点化部署方案,通过引入伪量化节点模拟低比特推理过程,使模型在训练阶段就适…

作者头像 李华
网站建设 2026/4/20 20:13:25

ROS机器人系统与URDF建模入门

一、机器人系统的核心组成一个完整的机器人&#xff0c;本质是“感知-决策-执行”的闭环系统&#xff0c;就像一个精密协作的生命体&#xff0c;四大核心模块各司其职、相互配合&#xff0c;缺一不可。从控制角度来看&#xff0c;分别是执行机构、驱动系统、传感系统、控制系统…

作者头像 李华
网站建设 2026/4/20 20:12:18

【python_高德地图_检查输入的地址是否详细】

python_高德地图_检查输入的地址是否详细 链接 import requests import jsondef main(address, city_info, gaode_key):url "https://restapi.amap.com/v3/geocode/geo"city json.loads(city_info)["provinceAndCity"]params {"key": gaode…

作者头像 李华