工业控制系统信息安全:从PLC协议分析到白名单防护落地
2026/9/30 8:46:06
“请手写一个 Redis 分布式锁。”
如果你直接写了redis.setnx(key, 1),面试官可能会让你直接回家等通知。
为什么?
今天,我们像剥洋葱一样,从青铜到王者,拆解分布式锁的7 种进化形态。
setnx// 1. 抢锁if(redis.setnx(lockKey,1)==1){try{// 业务逻辑...}finally{// 2. 释放锁redis.del(lockKey);}}finally没执行,锁永远删不掉。造成永久死锁!setnx+expireif(redis.setnx(lockKey,1)==1){redis.expire(lockKey,30);// 补一个过期时间try{...}finally{redis.del(lockKey);}}setnx和expire是两条命令,不是原子的。如果刚 setnx 完,网线被拔了,expire 没执行,依然死锁!SET NX PX(Redis 2.6.12+)Redis 官方终于看不下去了,把设置值和过期时间合并成了一条命令。
// 原子命令:SET lockKey requestId NX PX 30000Stringresult=jedis.set(lockKey,requestId,"NX","PX",30000);if("OK".equals(result)){try{...}finally{redis.del(lockKey);}}finally里的del,把 B 的锁给删了!为了防止删错锁,我们在 Value 里存一个 UUID (Client ID)。删除前判断一下:这是不是我的锁?
-- Lua 脚本保证原子性ifredis.call('get',KEYS[1])==ARGV[1]thenreturnredis.call('del',KEYS[1])elsereturn0end你自己写一个 Timer,每隔 10秒 检查一下,如果 A 还在跑,就给锁续命。
但是,写好这个多线程逻辑极其复杂,很容易由“解决死锁”变成“制造死锁”。
Redisson是 Redis 官方推荐的 Java 客户端,它内置了一个神器——看门狗 (WatchDog)。
使用代码(极其优雅):
RLocklock=redisson.getLock("myLock");try{// 1. 加锁 (默认 30s 过期,自动启动看门狗)lock.lock();// 2. 业务逻辑 (哪怕跑 1 小时,锁也不会断)Thread.sleep(60*60*1000);}finally{// 3. 解锁 (自动停止看门狗)lock.unlock();}看门狗原理图解:
WatchDog 核心逻辑:
场景:
为了解决这个极端问题(虽然概率极低),Redisson 实现了RedLock算法。
RLocklock1=redisson1.getLock("lock");RLocklock2=redisson2.getLock("lock");RLocklock3=redisson3.getLock("lock");RedissonRedLocklock=newRedissonRedLock(lock1,lock2,lock3);lock.lock();(注:RedLock 性能较差,且存在时钟跳变问题,业界争议较大,一般业务场景不推荐使用。)
在 99% 的业务场景下(电商秒杀、库存扣减、定时任务不重跑),Redisson 的默认锁(写法六)就是最终答案。
它完美解决了:
除非你是在做“金融级核心转账”,否则不要去碰 RedLock,过度设计是万恶之源。