1. 引言
在分布式系统中,多个服务实例可能同时操作共享资源,如果缺乏互斥机制,就会出现超卖、重复扣款、数据覆盖等问题。分布式锁正是为了解决这类跨进程、跨节点的并发竞争问题而设计的通用方案。本文围绕分布式锁的核心原理,给出基于 Redis 的完整代码实现,并讨论常见注意事项。
2. 核心原理
分布式锁的本质是让多个进程在共享存储上竞争一个「唯一标记」,谁拿到标记,谁就获得执行权。以 Redis 为例,最朴素的做法是利用SETNX命令:只有当 key 不存在时才能写入成功,写入成功的节点即获得锁。为了避免死锁,锁必须设置过期时间;为了避免误删他人锁,释放前要校验持有者标识。
3. 代码实现
下面给出一个基于 Redis 的分布式锁实现,使用 Java 语言和 Jedis 客户端,代码可直接复制运行。
import redis.clients.jedis.Jedis; import java.util.UUID; public class RedisLock { private Jedis jedis; private String lockKey; private String requestId; private int expireTime = 30000; // 锁自动过期时间,单位毫秒 public RedisLock(Jedis jedis, String lockKey) { this.jedis = jedis; this.lockKey = lockKey; this.requestId = UUID.randomUUID().toString(); } // 加锁:SETNX + 过期时间,保证原子性 public boolean tryLock() { String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime); return "OK".equals(result); } // 解锁:先校验持有者,再删除,防止误删他人锁 public void unlock() { String script = "if redis.call('get', KEYS[1]) == ARGV[1] " + "then return redis.call('del', KEYS[1]) " + "else return 0 end"; jedis.eval(script, 1, lockKey, requestId); } }使用示例:
Jedis jedis = new Jedis("localhost", 6379); RedisLock lock = new RedisLock(jedis, "order:12345"); if (lock.tryLock()) { try { // 执行临界区业务逻辑 System.out.println("获取锁成功,执行业务"); } finally { lock.unlock(); } } else { System.out.println("获取锁失败,稍后重试"); }4. 注意事项
第一,加锁和解锁必须保证原子性,避免「先 SETNX 再单独 EXPIRE」这种非原子写法。第二,释放锁前必须校验持有者标识,否则可能误删其他线程的锁。第三,业务执行时间不能超过锁的过期时间,否则锁提前失效会导致并发问题,必要时可引入看门狗续期机制。第四,在 Redis 主从架构下,主节点宕机可能导致锁丢失,对强一致性要求高的场景可考虑 Redlock 算法。
5. 总结
分布式锁是解决分布式并发竞争的基础组件。本文给出的 Redis 实现覆盖了加锁、解锁和防误删三个关键环节,代码简洁且可直接落地。实际生产环境中,建议优先使用 Redisson 等成熟客户端,它们内置了看门狗续期和 Redlock 支持,能进一步降低实现复杂度。