1. 分布式锁的核心需求与挑战
在分布式系统中,多个服务实例同时访问共享资源时,如何保证操作的互斥性是一个经典问题。想象一下多个收银员同时操作同一个库存系统,如果没有合理的互斥机制,就可能出现超卖或数据不一致的情况。
Redis的SETNX命令(SET if Not eXists)因其原子性和高性能成为实现分布式锁的常见选择。但单纯使用SETNX会遇到几个关键问题:
- 锁释放时的误删风险(自己的锁过期后误删别人的锁)
- 非原子操作导致的竞态条件
- 锁粒度控制不当造成的性能瓶颈
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础实现方案解析
2.1 锁的标识设计
锁的核心由两个部分组成:
java复制String lockName = String.format("prefix_%s_%s", tenantId, objectId);
String uuid = UUID.randomUUID().toString();
lockName(Key)的设计原则:
- 必须包含足够的信息来标识被保护的资源
- 示例中的
tenantId_objectId组合确保了:- 同一租户同一对象的操作会互斥
- 不同对象可以并行操作
- 前缀
prefix_的用途:- 避免与其他业务key冲突
- 方便通过
prefix_*模式搜索相关锁
uuid(Value)的作用:
- 作为锁持有者的唯一标识
- 防止锁被非持有者释放
- 推荐使用UUID而不是自增ID,因为:
- 无需中央协调生成
- 足够的唯一性保证
2.2 加锁逻辑实现
java复制if (!SquirrelClientUtil.setnx(lockName, uuid, 7200)) {
return "请勿重复操作";
}
关键点说明:
setnx的原子性保证了并发安全- 7200秒(2小时)的TTL是安全兜底,避免死锁
- 返回错误信息应包含足够上下文,方便排查
实际生产中建议将TTL设置为业务最长执行时间的2-3倍。例如业务通常执行需要5分钟,可以设置TTL为15-30分钟。
2.3 释放锁的标准流程
java复制Object lockValue = SquirrelClient
