技术的演变都是为了解决问题的,这也是技术演变吸引人的一点。
Redis分布式锁
分布式锁顾名思义 就是在分布式场景下 多台机器竞争一项资源去加锁
最简单的版本
首先就是最简单的版本,可以通过Redis的setnx命令(set if not exist)
setnx key value
这个命令会使Redis中如果不存在key就会创建值为value的key,存在的话就返回0
过期时间
如果获取锁的机器服务挂了呢?
其他机器:奶奶滴 怎么还不释放锁?
所以 有个兜底策略: 设置过期时间(挂了之后过段时间锁自动过期释放了)
此时可以用一个Redis自带的原子性的操作命令:
setnx key value nx ex 100
时间单位是秒
万一释放错锁了怎么办?
看这么一个场景:
涉及到两个问题:
- 任务还没处理完锁就过期释放了
- 释放掉了别人的锁
对应的解决办法:
- 锁的续约(根据业务加长时间,并且每过一段时间访问锁,如果存在就续约,增加时间)
- 给每个锁区分一下,这是谁加的锁(锁的value可以设置UUID等唯一确定的值)
优化过后的:
lua实现原子性
上面的一步删除的时候会发生什么错误?
当然 这个问题上面已经解决了,就是UUID+线程id作为key,已经不会被其他线程删掉了,但是这么看来这种错误也是挺危险的,作为一个兜底方案,我们可以用lua脚本实现原子性
lua脚本可以这么写
最后的防御
当然分布式的NPC原则告诉我们,没有完全安全的分布式锁(所以大家还是要根据业务来)
上面的场景中,主节点挂了咋办?
因为Redis是AP架构的,也就是说不能保证高一致性,主节点里的锁也许并没有同步到从节点里
这里可以用Redis官方的Red Lock 保证当前hash算法选择的节点的主从都有key了才会返回true
这种做法也有点“重”了,有些时候,杀鸡焉用牛刀