Redis分布式锁的核心是通过SETNX命令实现互斥锁:String key = "lockKey"; String value = UUID.randomUUID().toString() + Thread.currentThread().getId(); if(setnx(key, value)==1){ try{ //业务逻辑 }finally{ if(delnx(key,value)==1){ del(key); } } } 这套机制确保同一时刻只有一个线程获取锁,实现数据一致性。
1. Redis锁的基本原理
Redis锁机制是利用Redis的原子性操作(如SETNX命令)来实现分布式锁的。当多个客户端同时竞争同一个资源时,只有第一个客户端能成功设置key,其他客户端都会失败,从而实现互斥访问。SETNX命令的全称是SET if Not eXists,只有当key不存在时才设置成功,返回1,否则返回0。通过这个原子操作,避免了传统锁的竞争条件问题。
2. 实现Redis分布式锁
在Java中使用Redisson实现分布式锁非常简单:RLock lock = redisson.getLock("myLock"); lock.lock(); try { //处理业务 } finally { lock.unlock(); } Redisson内部自动处理了锁的续期和释放,确保即使服务宕机也不会死锁。相比SETNX+Lua脚本,Redisson更可靠。
3. 防止死锁:锁超时机制
Redis锁必须设置过期时间,避免死锁。使用SET key value NX PX 30000命令,同时设置key不存在且过期时间30秒。即使持有锁的线程崩溃,锁也会自动释放。获取锁后,开启守护线程每10秒续期一次PTTL检查剩余时间,小于30秒就EXPIRE续期,确保业务执行时间不超过锁时长。
4. 公平锁与非公平锁
Redis锁默认是非公平锁,先来先得不保证。Redisson支持公平锁模式:RLock fairLock = redisson.getFairLock("fairLock"); 通过Redis有序集合维护等待队列,实现FIFO,保证公平性。但公平锁性能略低,适用于严格顺序要求的场景。
5. 红锁(RedLock)算法
单机Redis锁有单点故障风险,Redlock使用N个独立Redis节点(建议5个),客户端需在N/2+1个节点上成功加锁才算获取锁。每个节点独立设置锁和超时。解锁时需在所有节点释放。即使部分节点故障,只要多数节点正常,锁仍有效。多节点提高了可用性。
6. 实际应用场景
在秒杀活动中,用Redis锁控制库存扣减:获取"product:1001:lock"锁,检查库存>0则扣减并释放锁。防止超卖。结合Lua脚本原子执行:local stock=redis.call('get','stock'); if(tonumber(stock)>0) then redis.call('decr','stock'); return 1; end。
FAQ
Q: Redis锁为什么比数据库锁高效?
A: Redis是内存数据库,SETNX是原子操作,锁竞争耗时微秒级,而数据库行锁涉及磁盘IO和事务日志,毫秒级。
Q: 如何避免误删其他线程的锁?
A: 锁值使用唯一UUID+线程ID,释放时用Lua脚本检查value匹配才删除。
Q: 单机Redis锁可靠吗?
A: 不完全可靠,主从切换可能丢失锁,建议用Redlock多节点。
Q: 锁续期怎么实现?
A: 加锁成功后启动定时任务,每watchdogTimeout/3续期一次,直到业务完成。