Redis分布式锁 | 青训营笔记

77 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

分布式锁要求:互斥,高可用,可重入

Redis里面的setnx命令,使用SET数据结构保证互斥,Lua脚本保证判断过程原子性

存在问题:

重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。
不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。
超时释放:我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患
主从一致性:如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。

为了防止锁过期时间过长或过短,使用Redisson中的分布式锁自带的自动续期机制

原理:提供了一个专门用来监控和续期锁的 "Watch Dog",如果操作共享资源的线程还未执行完成的话,Watch Dog 会不断地延长锁的过期时间,进而保证锁不会因为超时而被释放。

如果当前Redis节点挂掉了?

Redis集群方式共有三种:主从模式,哨兵模式,cluster(集群)模式

其中主从模式会保证数据在从节点还有一份,但是主节点挂了之后,需要手动把从节点切换为主节点。它非常简单,但是在实际的生产环境中是很少使用的。 哨兵模式就是主从模式的升级版,该模式下会对响应异常的主节点进行主观下线或者客观下线的操作,并进行主从切换。它可以保证高可用。 cluster (集群)模式保证的是高并发,整个集群分担所有数据,不同的 key 会放到不同的 Redis 中。每个 Redis 对应一部分的槽。

在上面描述的集群模式下还是会出现一个问题,由于节点之间是采用异步通信的方式。如果刚刚在 Master 节点上加了锁, 但是数据还没被同步到 Salve。这时 Master 节点挂了,它上面的锁就没了,等新的 Master 出来后(主从模式的手动切换或者哨兵模式的一次 failover 的过程),就可以再次获取同样的锁,出现一把锁被拿到了两次的场景。 锁都被拿了两次了,也就不满足安全性了。一个安全的锁,不管是不是分布式的,在任意一个时刻,都只有一个客户端持有。

Redis 的作者提出了名为 Redlock 的算法:至少 N/2+1 个Redis实例取到锁才算加锁成功