本地锁
浏览器把100w请求由网关随机往下传,在集群情况下,每台服务都放行10w请求过来,这时候每台服务都用的是本地锁是跨JVM的, 列如这些服务都没有49企业,此时有几个服务进行回原了打击在DB上面,那后期把这个服务部署了N台,N台用的都是自己的锁,是锁不住的
分布式锁第一阶段
让微服务都去公共位置去,列如Redis去抢占坑位利用setnx命令,如果是1了,操作成功,是1变成0操作失败,
问题:如下图如果抢到锁了 业务在执行期间机器宕机或停电了,后面解锁业务没有执行到,锁一直在,其他服务如果还想获取到这个锁,就会导致永远获取不到这个锁了,所以得引入过期时间
分布式锁第二阶段
引入过期时间后即使业务爆炸等10s以后再自行删除
问题:如果执行过期时间的时候停电了,导致这行代码没有设置上,所以加锁和过期时间必须是一起的保证原子性操作。
分布式第三阶段
为了保证原子性可以使用set key value EX “过期时间” NX,加锁+过期时间 用原子操作没问题了
极端情况:
假设锁10s过期,
- A运行9.5s业务结束开始删锁,给redis发请求。速度慢
- redis第10s锁过期自动删除,然后B抢到了锁,这个锁是B,B已经开始执行业务了
- B执行业务的时候,A删锁命令顺着网线爬到redis。直接调用del lock,删除了这个key。导致删除了B的锁的错误。B锁没有,其他C可能又进来。两个人都在执行业务,没锁住
分布式锁第四阶段
为了避免解别人的锁,利用UUID作为每个线程自己锁的唯一值
问题解除锁的时候可能会解到别人的锁
分布式锁终极阶段
利用Lua脚本删除锁
使用redisson
private long lockWatchdogTimeout = 30 * 1000;
看门狗如何自动续期
Redisson看门狗机制, 只要客户端加锁成功,就会启动一个 Watch Dog。
redisson底层有个 看门狗时间 = lockWatchdogTimeout ; 30s;每10s进行一次 喂狗
1,scheduleExpirationRenewal(threadId); 定时重新设置过期时间
底层使用 Timeout;定时任务。每隔internalLockLeaseTime / 3执行重新设置超时时间的任务;
超时时间设置好以后,递归调用自己,又启动一个定时任务
定时任务是在 internalLockLeaseTime[30000] / 3 毫秒以后执行
每10s执行一次任务。
2,如果服务宕机了,Watch Dog 机制线程也就没有了,此时就不会延长 key 的过期时间,到了 30s 之后就会自动过期了,其他线程就可以获取到锁。