介绍之前用redis实现分布式锁的时候,是基于单Redis实例的,也就是说Redis本身存在单点故障。Redis的官方文档介绍了一个“自认为”合理的算法,Redlock来实现分布式Redis下的分布式锁。MartinKleppmann写了一篇分析Redlock的文章。然后redis的作者在这里写了一个反驳。快点。Redlock实现库JavaRedissonStar9458C#RedLock.netStar259Goredsync.goStar249虽然后面的算法是一样的,但是点赞数真的很有说服力。单点Redis锁首先简单回顾一下单点Redis锁是如何实现的。获取锁SETresource_namemy_random_valueNXPX30000客户端A在Redis上设置了特定的键值对,同时给出超时时间(避免死锁)。其他客户端访问时,先检查key是否已经存在,value是否等于my_random_value。如果存在则等待,否则会成功并执行业务代码。resource_name和my_random_value为所有客户端所知并共享。释放锁ifredis.call("get",KEYS[1])==ARGV[1]thenreturnredis.call("del",KEYS[1])elsereturn0end比较key得到的对应值是否相等,如果相等则Delete(释放),否则返回失败。我之前也写过一篇文章。单点Redis锁的缺陷其实很明显。如果只有一个Redis实例,这个就会挂掉,所有依赖它的服务都会挂掉。显然不适合大型应用。简单的Redis主从架构遇到的问题为了避免单点故障,我们给Redis做了一个Master/Slave的主从架构,一Master一Slave。下面就会遇到这样的问题。下面是使用场景。ClientA获取了Master的锁。Master在同步这个数据给Slave的时候就挂了(因为Master和Slave之间的同步是异步的)。奴隶成为主人。客户端B使用相同的键和值获取锁。分布式锁失效Redlock算法假设我们有N(假设5)个Redismaster实例,所有节点相互独立,业务系统只是简单调用,没有消息重传之类的其他辅助系统。我们来模拟一下算法:1.客户端获取服务器的当前时间t0,单位为毫秒。2.使用相同的key和value依次从5个实例获取锁。客户端在获取锁的时候,设置了一个超时时间,这个超时时间比业务锁需要的时长要短很多。例如,假设锁定需要10秒,超时可以设置为5-50毫秒。这样就避免了某个Redis本身已经挂了,但是client一直在尝试获取锁的情况。超时后,直接跳转到下一个节点。3、客户端通过当前时间(t1)减去t0,计算出获取锁所消耗的时间t2(=t1-t0)。只有当t2小于锁的服务有效时间(即第二步中的10秒),并且客户端至少在3(5/2+1)个平台上获取到锁,我们才认为获取到锁是成功的。4、如果已经获取到锁,则锁的服务有效时间为10s-t2。5、如果客户端没有获取到锁,可能是在大于等于N/2+1个实例上没有获取到锁,或者有效时间(10s-t2)为负数,我们会尝试释放锁,即使它在该节点上不可用。锁的释放比较简单,删除所有实例上对应的键即可。喜欢文章的可以关注一下,感谢阅读!
