ZooKeeper: wait-free coordination for internet-scale systems 论文阅读笔记

本文深入探讨ZooKeeper的工作原理,包括其协调原语、ZAB协议、读写请求处理及时间戳一致性保障。通过分析ZooKeeper如何利用ephemeral node实现服务器状态维护和锁机制,展示了其在分布式系统中的应用。

ZooKeeper: wait-free coordination for internet-scale systems 论文阅读笔记

有些表述绕来绕去,似乎也没什么内容
个人感觉就2点:

  • leader 把写请求转换成幂等的写事务
  • leader 广播写事务的通道是 FIFO 的

特征

  • client 请求(大多是读)
    • 对同一 client 的请求是 FIFO 执行的
    • 写请求由 leader 串行执行(ZAB协议)
    • 读请求可以向任何 server,对 client 满足 时间戳一致性(读到的 server 保证自己的时间戳不小于 client)
  • 协调原语
    • zookeeper 是一个 协调内核(coordination kernel),提供 API 给 dev,用来设计 协调原语(coordination primitive)
    • 不提供 lock

Zookeeper 服务

  • zookeeper 内存中的数据结点叫做 znode
  • znode 结构上类似 linux 文件系统;所有 znode 都存储数据;除了 ephemeral znode,都可以有孩子节点
  • client 与 zookeeper 的连接建立在 session 之上
    • session 有 timeout
    • zk 支持 client 将一个 session 透明地在 server 间转移
  • zookeeper 向 client 提供一个抽象的 znode 集合
    • client 可以创建 znode
      • regular:永久性的,可以删除
      • ephemeral:生命周期在本次 session 之内,也可能 session 结束之前被 client 删除
  • zookeeper 提供 watch 和 notify 服务(session 内的一次性触发服务)

znodes 通常不用来存储数据,而是用来维护应用程序的 metadata,说白了就是“应用程序使用 zk 来管理配置文件

API

    • 返回是否存在
    • 返回数据
    • 返回 children
    • 支持 watch 与 notify
    • 基于 version number 的 CAS
  • 同步
    • 同步在此之前的 leader 上的所有写操作(主要用在读 server 前)

对 znode 的操作总是用 绝对路径,减少 server 的维护负荷

序保证

  • 所有写操作都在 leader 串行化执行
  • client 的 request 被 FIFO 执行

举了几个例子,就是如何用 zk 做通信与同步(之前看了些分布式全局快照,这里就没什么意思了)

  • 使用 ephemeral node 来维护一群 server 的状态,每个 server 在自己的 session 建立 ephemeral node,整个集群的状态就在一个 subtree 下
  • 用 file 的存在与否来模拟互斥锁,watch 这个 file 来得知锁被释放(惊群效应)
  • 给要用锁的 server 编号,每次编号最小的拿锁,避免惊群效应(这里每个 server 都有自己的文件,编号最小视为拿锁,删除文件视为释放锁)
    • client 一上来先建个文件,并获得编号
    • 如果自己的编号是最小的,那么直接返回(视为 lock 成功)
    • 每个 client 都 watch 编号比自己小1的(避免惊群)
    • 释放锁的时候删除文件
  • 读写锁:文件命名区分,写锁流程照常,读锁只要没有编号比自己小的写锁就成功

Zookeeper 实现

在这里插入图片描述

  • Request Processor
    • leader 广播的写事务是 idempotent
    • 原文:When the leader receives a write request, it calculates what the state of the system will be when the write is applied and transforms it into a transaction that captures this new state.
    • 我猜应该是 leader 把所有写操作转换为写具体值。比如 update x = x +1 转换成 update x = x0,这样写事务就是幂等的了,之后只要保证 FIFO 执行
  • Atomic Broadcast
    • leader 广播写操作到 server,保证通道是 FIFO
    • 新 leader 广播之前,保证收到了之前 leader 的所有广播
  • Replicated Database
    • 每个 server 都有 replicated database (in memory),使用 WAL 和 定期snapshot 回放
    • snapshot 生成时深度优先遍历 znode,不上锁
      • snapshot 的状态可能不存在:记录了生成 snapshot 开始之后的写事务,但由于写事务是幂等的,所以回放的时候不影响
  • client 交互
    • 读请求附带时间戳 zxid
      • 如果 server 本地时间戳不小于读请求,那么可以直接本地读,不一定读到最新数据,但是性能高
      • 如果 client 要求最新数据,可以先 sync,然后 read(保证同步到 sync 为止新的数据)
    • session timeout
      • 在空闲期,client 在 timeout/3 处发送 heartbeat 给 server,如果之后的 timeout*2/3 没有收到回复,那么就换 server

Reference

<think>我们正在分析一个Maven项目(com.shdky:mrs-measure-listener)的依赖树,特别是关于ZooKeeper的依赖以及可能存在的重复依赖问题。用户之前提到了audience-annotations的依赖问题,现在可能是在类似背景下出现的ZooKeeper依赖问题。 步骤: 1. 生成依赖树:使用`mvn dependency:tree`命令,并可以配合`-Dincludes`参数来过滤出我们关心的依赖(如ZooKeeper相关的依赖和可能冲突的依赖)。 2. 分析依赖树:查看ZooKeeper的版本,以及是否有多个不同的版本被引入(即重复依赖),同时注意传递依赖带来的冲突。 3. 解决冲突:如果存在多个版本,需要确定保留哪个版本(通常选择较新的稳定版本),并通过依赖管理(dependencyManagement)或排除(exclusion)来解决。 假设用户已经遇到了类似之前audience-annotations的冲突问题,现在在ZooKeeper上也可能出现。 具体操作: 1. 生成依赖树命令(在项目根目录下执行): ``` mvn dependency:tree -Dverbose -Dincludes=org.apache.zookeeper:*,*:zookeeper ``` 或者更精确地指定groupId和artifactId(如果知道): ``` mvn dependency:tree -Dverbose -Dincludes=org.apache.zookeeper:zookeeper ``` 使用`-Dverbose`参数可以显示所有冲突的依赖(即被忽略的依赖也会显示)。 2. 分析依赖树输出: 在输出中,我们会看到以树形结构展示的依赖关系。重点关注: - 直接依赖和传递依赖中引入的ZooKeeper版本。 - 是否有多个版本出现?如果有,Maven会根据依赖调解规则(最近路径优先,第一声明优先)选择一个版本,而其他版本会被忽略(但在verbose模式下会显示为omitted for conflict)。 3. 解决冲突: 如果存在多个版本,我们可以在项目的pom.xml中通过以下方式解决: a. 使用`<dependencyManagement>`统一管理版本。 b. 在直接引入ZooKeeper的依赖中明确指定版本(如果项目直接依赖了ZooKeeper)。 c. 排除传递依赖中的旧版本。 示例:假设依赖树显示有两个版本的ZooKeeper:3.4.14和3.6.3,而3.4.14是通过某个传递依赖引入的旧版本,我们希望使用3.6.3。 方法一:在dependencyManagement中指定版本(推荐,尤其对于多模块项目): ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.3</version> </dependency> </dependencies> </dependencyManagement> ``` 方法二:排除旧版本的传递依赖: ```xml <dependency> <groupId>some.group</groupId> <artifactId>some-artifact</artifactId> <version>X.Y.Z</version> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> ``` 4. 验证:再次运行依赖树命令,确认现在只有一个版本的ZooKeeper被使用。 另外,用户可能还关心其他重复依赖(比如之前遇到的audience-annotations)是否也被解决。我们可以用类似的方法处理。 注意:如果项目使用了Spring Boot,它可能通过parent POM或dependency management已经管理了ZooKeeper的版本。此时,我们应该检查Spring Boot的版本和它管理的ZooKeeper版本,尽量保持一致。 如果用户没有提供具体的依赖树输出,我们可以给出一个示例分析: 假设依赖树输出片段如下: ``` [INFO] com.shdky:mrs-measure-listener:jar:1.0.0 [INFO] +- org.springframework.boot:spring-boot-starter:jar:2.5.6 (compile) [INFO] | \- ... [INFO] +- org.apache.zookeeper:zookeeper:jar:3.6.3 (compile) [INFO] | \- ... (传递依赖) [INFO] \- com.some.dependency:some-artifact:jar:1.0.0 (compile) [INFO] \- org.apache.zookeeper:zookeeper:jar:3.4.14 (compile) ``` 这里,我们直接依赖了3.6.3,但是通过some-artifact传递依赖了3.4.14。由于3.6.3在依赖树中更靠近根节点(路径更短)或者声明更早,Maven会选择3.6.3。但是,为了明确和避免潜在的冲突,我们可以排除some-artifact中的zookeeper依赖。 在pom.xml中: ```xml <dependency> <groupId>com.some.dependency</groupId> <artifactId>some-artifact</artifactId> <version>1.0.0</version> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> ``` 这样,依赖树中就只有一个版本的zookeeper(3.6.3)了。 如果用户的项目中出现了其他重复依赖,也可以用同样的方法处理。 最后,建议用户运行`mvn clean install`验证构建是否成功,以及运行时是否出现类冲突(如NoClassDefFoundError, NoSuchMethodError等)。 由于用户之前提到过audience-annotations的问题,这里也需要注意,ZooKeeper本身可能依赖了audience-annotations,所以如果之前已经统一了audience-annotations的版本,那么这里应该已经一致了。如果不一致,同样需要在dependencyManagement中统一。 下面,我将按照用户要求,生成一个关于Maven依赖树分析的相关问题列表。</think>### Maven依赖树分析:`com.shdky:mrs-measure-listener`的ZooKeeper与重复依赖问题 #### 1. **生成依赖树** 执行命令获取完整依赖树: ```bash mvn dependency:tree -Dverbose -Dincludes=org.apache.zookeeper:*,*:zookeeper ``` `-Dverbose`参数显示冲突依赖,`-Dincludes`过滤ZooKeeper相关依赖。 #### 2. **典型问题场景分析** ##### 场景1:多版本ZooKeeper冲突 ```text [INFO] com.shdky:mrs-measure-listener:jar:1.0.0 [INFO] +- org.apache.curator:curator-framework:jar:5.3.0 (compile) [INFO] | \- org.apache.zookeeper:zookeeper:jar:3.7.1 (compile) [INFO] \- com.alibaba.dubbo:dubbo-registry-zookeeper:jar:2.7.15 (compile) [INFO] \- org.apache.zookeeper:zookeeper:jar:3.4.14 (compile, omitted for conflict with 3.7.1) ``` **问题**: - Curator引入ZooKeeper 3.7.1 - Dubbo引入ZooKeeper 3.4.14(被Maven忽略) **风险**: 低版本功能缺失(如ACL权限控制) API不兼容导致`NoSuchMethodError`[^1] ##### 场景2:传递依赖重复 ```text [INFO] +- org.apache.hbase:hbase-client:jar:2.4.9 (compile) [INFO] | \- org.apache.zookeeper:zookeeper:jar:3.4.14 (compile) [INFO] \- org.apache.kafka:kafka-clients:jar:3.2.1 (compile) [INFO] \- org.apache.zookeeper:zookeeper:jar:3.8.0 (compile) ``` **问题**: 三个不同版本的ZooKeeper共存(3.4.14, 3.7.1, 3.8.0) #### 3. **解决方案** ##### 步骤1:统一版本(推荐) ```xml <dependencyManagement> <dependencies> <!-- 统一使用ZooKeeper最新稳定版 --> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.8.0</version> </dependency> <!-- 解决相关依赖冲突 --> <dependency> <groupId>org.apache.yetus</groupId> <artifactId>audience-annotations</artifactId> <version>0.12.0</version> </dependency> </dependencies> </dependencyManagement> ``` ##### 步骤2:排除旧版本 ```xml <dependency> <groupId>com.alibaba.dubbo</groupId> <artifactId>dubbo-registry-zookeeper</artifactId> <version>2.7.15</version> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> ``` #### 4. **验证结果** ```bash # 验证依赖树 mvn dependency:tree -Dincludes=org.apache.zookeeper:* # 预期输出 [INFO] org.apache.zookeeper:zookeeper:jar:3.8.0 (compile) ``` #### 5. **冲突检测工具** ```xml <!-- 添加maven-enforcer-plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>enforce</id> <goals><goal>enforce</goal></goals> <configuration> <rules> <dependencyConvergence/> <banDuplicateClasses> <ignoreClasses> <ignoreClass>org.slf4j.*</ignoreClass> </ignoreClasses> </banDuplicateClasses> </rules> </configuration> </execution> </executions> </plugin> ``` 此插件将阻止构建并报告: - 版本冲突(dependencyConvergence) - 重复类文件(banDuplicateClasses) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值