Redis分布式锁
单redis实例分布式锁
- set
格式:SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
EX 过期时间,单位秒
PX 过期时间,单位毫秒
NX – Only set the key if it does not already exist.
XX – Only set the key if it already exist
例如:set key value NX PX 3000 - setnx
SETNX KEY_NAME VALUE
没有才创建 - setex
SETEX KEY_NAME TIMEOUT VALUE
创建并设定过期时间,如果key存在,用新value替换
实现方式:
1:单独用set NX EX
2:使用setnx和setex组合
多redis实例分布式锁的问题
单台redis服务无法提供高可用,如果多台redis集群服务,实现分布式锁问题
场景:
A、B、C三个节点的redis组成的redis集群,业务在A节点创建分布式锁,如果这个锁还未同步到B、C两个节点,此时A节点死掉,B、C两个节点组成集群,导致业务A的锁丢失问题。
Redlock 算法
前提:假设有N个redis节点
客户端加锁:逐个向节点去申请锁(set key value),如果在多数节点申请成功,则视为加锁成功,最好并行
注意要点:
1:向单个节点申请加锁的超时时间要远小于锁的有效时间
2:锁的有效期为设定的有效期减去逐个申请锁的时间消耗
3:如果逐个向节点申请锁的时间过长,导致锁的有效期为0,视为申请失败
4:获取锁失败释放锁,释放锁要求在所有节点释放锁,不论节点是否申请锁成功
5:当一个客户端不能获得锁时,它应该在随机延迟后再次尝试,避免大量客户端同时获取锁的情况出现,这种情况下可能发生脑裂(split brain condition),导致大家都获取不了锁
问题:如果各节点的时间不一致,存在时间差问题。
解决:必须确保客户端在 锁过期时间-跨进程的时间差(clock drift) 时间内做完自己所有的工作
系统时钟漂移
linux提供了两个系统时间:clock realtime和clock monotonic
- clock realtime也就是xtime/wall time,这个时间是可以被用户改变的,被NTP改变,gettimeofday取的就是这个时间,redis的过期计算用的也是这个时间
- clock monotonic,直译过来是单调时间,不会被用户改变,但是会被NTP改变
- 最理想的情况时,所有系统的时钟都时时刻刻和NTP服务器保持同步,但这显然是不可能的。
导致系统时钟漂移的原因有两个:
1:系统的时钟和NTP服务器不同步。这个目前没有特别好的解决方案,只能靠运维
2:clock realtime被人为修改。在实现分布式锁时,不要使用clock realtime。不过很可惜,redis使用的就是这个时间
备注:
1:NTP服务器【Network Time Protocol(NTP)】是用来使计算机时间同步化的一种协议,它可以对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正