比较
性能和可用性
Redis加锁性能更高,但会出现锁丢失数据不一致问题;ZK加锁性能没有那么高,但集群通过ZAB协议(写入时原子广播,故障恢复时zxid最大作为Leader节点)保证了数据一致性。
Redis主从/哨兵或者cluster模式下都是AP的,保证了可用性而采用master异步复制数据给slave,存在master加锁成功之后挂了,slave未同步master数据之后再升级为新的主节点,之前的master锁数据就丢失的场景。
- Redis也提供了RedLock算法来解决锁丢失问题,写入奇数个master节点,但性能差且对集群部署方式有要求。
- ZK集群是CP模式,写leader节点数据的过程中需要同步广播数据到follower节点,保证了数据一致性,不会出现数据不一致的场景。但是如果leader节点挂了,重新选举的过程中zk集群不可使用,牺牲了可用性。
加锁原理
- Redis加锁(Redisson)是利用了hash结构存放,key(hash的field)是uuid:threadid,value是重入次数来实现的。默认Redisson是非公平锁,其他被阻塞的客户端订阅锁释放或者自旋重试获取锁。
- Zk是创建临时顺序节点来实现分布式锁的,多个客户端会在写入的时候判断写入的序号是否为当前临时节点的第一个,不是的话注册Watcher监听上一个序号的临时节点,wait()实现阻塞,等上一个节点删除之后触发notifyAll()唤醒来重新尝试加锁。
锁续期
Redis的Redisson实现分布式锁在重入加锁、重入解锁有锁续期逻辑,且调用默认的lock方法时会注册一个watchdog任务来完成锁续期的逻辑。所以可以支持锁续期;ZK默认不支持锁续期,当然zk是在执行完成之后去释放锁,不存在业务执行超过锁时间的问题。
公平锁
- Redisson要实现公平锁还得借助增加list(排队)和zset(加锁超时),复杂度变高。
- zk监听上一个序号的临时节点,支持公平锁。先创建临时节点的先加锁。