这篇是Redis 学习笔记系列的高可用篇,也就是实战篇,所有的redis 系类更新首先是日常工作笔记和Redis 源码系列。[先挖坑,后面慢慢填吧,雾...]
分布式锁的实现要点是什么?
分布式锁实现四要点:
- 互斥性
- 抗死锁性
- 对称性
- 可靠性
为什么要引入Owner 概念?
- 因为不加入Owener -- 也就是锁的持有者信息,那么锁就无法实现堆成性,即一把锁的加解锁可以是凉饿用户,分布式锁得对称性也就无法保障
如何保障事务原子性?
redis 本身提供有事务操作,但是不保障原子性,这个事务执行总如果中间有错误,事务不会打断也不会回滚而是就绪执行剩下得事务。无法保障事务原子性
目前主流做法是使用Lua 脚本作事务脚本,用脚本操作redis 来保证事务. 因为redis 核心业务时单线程的,在执行Lua 脚本时会整脚本当作一个作业事务来处理,所以能保证原子性,但是Lua 事务粗错不会回滚,只会中断。
可靠性如何保障
异常情况: 节点挂了、业务时间超时、网络延迟...
对于挂了
- 主从容灾,从节点挂有其他节点,主节点挂有从节点顶上变主节点....
- 主从切换可以使用哨兵模式 主从模式再同步数据时会有一定的数据延时,一致性保障不如分布式强
- 分布式多机部署
- 也就是所谓的 分布式存储方案,比如引入RedLock,但是节点个数建议是单数个
RedLock
是什么?
一种分布式锁算法,由 Redis 的作者设计,用于在分布式系统中实现可靠的锁机制。它的设计解决了单一 Redis 实例作为分布式锁可能出现的单点故障问题。-- 也就是客户端从master 获取锁后 master未来的及将锁信息同步给其他节点就挂了,新节点顶替,另一个客户端获取相同得资源获取成功得问题。
实现原理:
- 多节点加锁: RedLock 在多个独立的 Redis 实例上同时尝试获取锁。通常建议使用奇数个 Redis 实例(如 5 个),以确保系统具有较好的容错性。
- 多数节点同意: 系统只有在获得了大多数 Redis 实例的锁(即 N/2 + 1 个节点,N 为节点总数)之后,才认为成功获取了分布式锁。这样即使部分 Redis 实例发生故障,整体锁服务仍然可用。
- 时间同步: 为防止客户端在持有锁的过程中发生故障而导致锁无法释放,RedLock 会在获取锁时设置一个超时时间。如果客户端在锁超时之前未能完成任务并释放锁,其他客户端可以在锁超时后重新尝试获取。 -- 针对业务超时未完成导致锁被自动过期释放这一为题可引入看门狗,看门狗发定期检查业务线程作业情况,发现仍未完成,则续期锁
- 锁释放: 释放锁时,客户端需要向所有 Redis 实例发送释放锁的命令,以确保所有实例上的锁都被清除。
工作原理
- 获取当前unix毫秒时间戳(业务开始时间戳),设置锁TTL(TTL > 业务耗时 + 成功获取锁耗时 + 时钟漂移)。
- 使用相同得kv值, 依次向各分节点获取锁(获取前设置这次向该节点获取锁得超时时间,避免死等,超时放弃,改向下一个节点重复此操作)更新锁获取时间戳。
- 锁获取时间戳减业务开始时间戳 = 锁申请耗时时间戳
- 业务锁获取成功(获取成功条件见下,假设有单数各节点N,成功获取锁的节点个数M)
- M >= (N/2) + 1
- 剩余业务可用时间 > (锁TTL - 锁获取总时间 - 时钟漂移) 比如:TTL 是10s,获取所有锁用了 2s,则真正锁有效时间为 8s;
- 如果锁获取失败 向所有节点发送解锁操作(包括获取失败的节点,因为不知道时网络原因导致超时判断的失败还是真失败...). -- 必要时可以使用双删(删了后等一会再删),或者引入看门狗
- 锁获取失败重试;等一会再来获取看看(重试次数应有限制避免过度浪费资源)...
REDLOCK 真的可靠吗? -- NCP 可靠性探讨
N
N - network delay 网络延迟;这里讲的时获取锁因为网络延迟导致时间关系问题,以及怎么直到获取成功?
- 设置锁TTL 时可以多预估(冗余)一段时间
- redis 会有回包反馈锁获取情况
- 设置获取等待超时时间,超时算失败
总的来说能一定程度缓解网络延迟问题
P
P - Process Pause (进程阻塞/暂停); 这里讲的时获取锁后,业务处理超时(比如业务处理中GC,中间被更高优先级的作业任务打断挂起...), 之后Redis中的锁超时了(这种情况可以使用看门狗,但看门狗不是万能的比如作业进程不会看门口了,看门狗以为作业进程死了,那没得解),之后这个超时得进程从超时中恢复了过来,另一个进程申请走了锁,这时后就会有看起来凉饿进程都获取到锁得情况。这种也算无解
C
C - Clock Drift (时钟漂移);为了方便这里假设一种极端情况(但其实概率很小),假设有5个节点,5个节点都发生了时钟漂移(系统时钟突然从某个时间突然变到某个时间),导致锁失效,这是后另一个进程获取了锁,这样就会看起来两个进程都拿到了锁。这中情况也算是无解。
总结
RedLock 其实也扛不住上面极端得论述情况,所以要实现一个相对可靠的分布式锁,还需要根据业务出发,业务本身要可重入,幂等才行。
PS Red Lock 是一种比较重的锁方案,一般业务很少用到。