基于Zookeeper的锁

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 【10月更文挑战第2天】

时钟问题的解释

不需要完全一致,允许有误差,只要是不超过误差范围锁失效时间就可以
对于对方提到的时钟修改问题,反驳:

  • 手动修改时钟:停止这种做法
  • 时钟跳跃:通过恰当的运维,保证机器时钟不会大幅度跳跃,每次通过微小的调整来完成

    网络延迟和GC问题

    在Redlock流程里,如果步骤1~3发生了网络延迟、进程GC等耗时很长的异常情况,那么步骤3里是可以检测出来的,如果time2-time1超过了锁设置的超过时间,会认为加锁失败并释放所有锁。
    如果对方认为,发生网络延迟、进程GC是在步骤3以后,也就是 客户端拿到了锁,但是在操作共享资源的过程里出现了问题导致锁失效,那任何的锁服务如zk,都有类似的问题

总结一下就是:

  • 客户端在拿到锁之前,无论经历什么耗时长问题,Redlock 都能够在步骤3检测出来
  • 客户端在拿到锁之后,发生 NPC,那 Redlock、Zookeeper 都无能为力

质疑fecing token机制

第一,这个方案必须要求要操作的共享资源服务器有拒绝旧token的能力
比如,操作MySQL,从锁服务里拿到一个递增数字的token,然后客户端要带着这个token去改MySQL的某一行,就需要利用MySQL的事务隔离性做

UPDATE table T SET val = $new_val, current_token = $token WHERE id = $id AND current_token < $token

但是如果操作共享资源是向磁盘上写文件,或是发HTTP请求呢?这种方案并不可行,大部分要操作的资源服务器,都没有互斥能力
第二,Redlock已经提供了随机值,利用随机值,也可以达到和fencing token相同的效果,类似CAS

  1. 客户端使用 Redlock 拿到锁
  2. 客户端在操作共享资源之前,先把这个锁的 VALUE,在要操作的共享资源上做标记
  3. 客户端处理业务逻辑,最后,在修改共享资源时,判断这个标记是否与之前一样,一样才修改

还是以 MySQL 为例:

  1. 客户端使用 Redlock 拿到锁
  2. 客户端要修改 MySQL 表中的某一行数据之前,先把锁的 VALUE 更新到这一行的某个字段中(这里假设为 current_token 字段)
  3. 客户端处理业务逻辑客户端修改 MySQL 的这一行数据,把 VALUE 当做 WHERE 条件,再修改
UPDATE table T SET val = $new_val WHERE id = $id AND current_token = $redlock_value

两个客户端通过这种方案,先标记再检查+修改共享资源,那这两个客户端的操作顺序无法保证,而用 Martin 提到的 fencing token,因为这个 token 是单调递增的数字,资源服务器可以拒绝小的 token 请求,保证了操作的顺序性
Redis 作者对于这个问题做了不同的解释:分布式锁的本质,是为了互斥,只要能保证两个客户端在并发时,一个成功,一个失败就好了,不需要关心顺序性

基于Zookeeper的锁

  1. 客户端 1 和 2 都尝试创建临时节点,例如 /lock
  2. 假设客户端 1 先到达,则加锁成功,客户端 2 加锁失败
  3. 客户端 1 操作共享资源
  4. 客户端 1 删除 /lock 节点,释放锁

Zk采用了临时节点,保证客户端1拿到锁后,只要连接不断,可以一直持有锁;而如果客户端1异常崩溃了,这个临时节点会自动删除,保证了锁一定会被释放。
如果保证连接不断呢?客户端1会和Zk服务器维护一个Session,这个Session依赖客户端的定时心跳来维持连接。如果Zk长时间收不到客户端的心跳,就认为这个Session过期了,也会把这个临时节点删除。

所以Zk也无法保证进程GC、网络延迟下的安全性

也就是说,一个分布式锁,极端情况下,不一定是安全的

Zk的优点:

  • 不需要考虑锁的过期时间
  • watch机制,加锁失败,可以watch等待锁释放,实现乐观锁

Zk的缺点

  • 性能不如Redis
  • 部署运维成本高
  • 客户端与Zk长时间失联,锁会被释放

总结

  1. 使用分布式锁,在上层完成互斥目的,虽然极端情况下锁失效,但是可以最大程度把并发量阻挡在上层,减轻操作资源层的压力
  2. 对于要求数据绝对正确的业务,在资源层做好兜底,设计思路可以借鉴fencing token
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
24天前
|
存储 运维 NoSQL
分布式读写锁的奥义:上古世代 ZooKeeper 的进击
本文作者将介绍女娲对社区 ZooKeeper 在分布式读写锁实践细节上的思考,希望帮助大家理解分布式读写锁背后的原理。
|
7月前
|
监控 安全 Apache
Apache ZooKeeper - 使用ZK实现分布式锁(非公平锁/公平锁/共享锁 )
Apache ZooKeeper - 使用ZK实现分布式锁(非公平锁/公平锁/共享锁 )
356 1
|
7月前
|
存储 分布式计算 大数据
【云计算与大数据技术】分布式协同系统Chubby锁、ZooKeeper在HDFS中的使用讲解(图文解释 超详细)
【云计算与大数据技术】分布式协同系统Chubby锁、ZooKeeper在HDFS中的使用讲解(图文解释 超详细)
199 0
|
Java Linux API
Zookeeper学习---3、服务器动态上下线监听案例、ZooKeeper 分布式锁案例、企业面试真题
Zookeeper学习---3、服务器动态上下线监听案例、ZooKeeper 分布式锁案例、企业面试真题
|
Java
java的锁和zookeeper的锁
java的锁和zookeeper的锁
71 0
|
索引
ZooKeeper 分布式锁 Curator 源码 05:分布式读写锁和联锁
Curator 同样支持分布式读写锁 和联锁,只需要使用 InterProcessReadWriteLock 即可,来一起看看它的源码以及实现方式。
175 0
|
NoSQL Redis
ZooKeeper 分布式锁 Curator 源码 04:分布式信号量和互斥锁
分布式信号量,之前在 Redisson 中也介绍过,Redisson 的信号量是将计数维护在 Redis 中的,那现在来看一下 Curator 是如何基于 ZooKeeper 实现信号量的。
165 0
|
Java
ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁
在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的?
142 0
|
Java
ZooKeeper 分布式锁 Curator 源码 02:可重入锁重复加锁和锁释放
加锁逻辑已经介绍完毕,那当一个线程重复加锁是如何处理的呢?
145 0