前段时间看了## 基于Redis的分布式锁到底安全吗(上)?和## 基于Redis的分布式锁到底安全吗(下)?,文章谈了Martin和Antirez关于Redlock安全性的讨论,本文整理下讨论内容,思考了如何实现真正意义分布式锁的方式,欢迎一起交流。
首先看下Martin和Antirez的争论观点: Martin的观点主要是分为两部分:1)当锁过期时,客户端A、B都会获取操作共享资源的权限,从而出现冲突,解决的方法是增加递增token,具体来说,客户端成功获取到锁时会得到一个token,后续客户端访问共享资源的时候带着这个token,redis根据它进行检查,拒绝掉延迟到来的访问请求,即只响应当前拿到token的请求;2)redlock存在安全问题,当出现时钟跳跃或者GC时会存在锁失效情况。
Antirez反驳观点也可以分为两部分:1)token这块可以采用随机方式,只要保证唯一即可,redis是提供的;2)时钟跳跃是存在问题,但人为的可以避免;GC引发的两种情况,如果是加锁过程太久、超时,redlock会有检测机制发现,如果是加锁后,访问资源期间超超时就不可避免,并且这是分布式锁都有的问题。
下面谈下个人关于分布式锁的想法: 首先分布式锁没有绝对的安全,在极端情况下,无论哪种方式,你都无法保证拿到锁的时候或者正在访问共享资源的时候,锁是不是恰好过期了,比如:锁过期时间设置的很短、只有50ms,很可能所有客户端都拿到锁、都去操作共享资源,续期只是减少锁失效的一种手段。
其次如果要想实现真正意义上的分布式锁,感觉实现上会比较复杂,想到的一个方案是: 1)增加token判断,确保操作共享资源的客户端一定是持有锁的客户端,即操作人必须是锁的持有者; 2)每次操作共享资源前都要确保锁未过期,并且在操作共享资源期间,锁过期和共享资源操作必须保证事务,比如:共享数据操作期间,恰好锁过期了,此时锁服务器就要出手,让锁一直持有、不能过期直到共享资源操作完,但这块就很复杂了,特别是锁是多实例的方式,比如:Redlock、Zookeeper、ETCD等,这些支持就更复杂了。
所以对于分布式锁使用要看场景,如果是追求效率,可以使用,增加个幂等即可;如果是追求绝对安全、准确,建议不要使用。