[译] Java 和 etcd: 因为 jetcd 最终走到了一起

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 可靠的键值存储为分布式系统提供了一致性配置和协调的公共基础。etcd 项目就是一个这样的系统,这是一个由 CoreOS 创建的开源键值存储系统。它是许多生产级分布式系统的核心组件和 Kubernetes 等项目的数据存储中心。

原文地址:Java and etcd: together at last, with jetcd
原文作者:Fanmin Shi
译文出自:掘金翻译计划
本文永久链接:github.com/xitu/gold-m…
译者:mingxing
校对者:xiantang


可靠的键值存储为分布式系统提供了一致性配置和协调的公共基础。etcd 项目就是一个这样的系统。这是一个由 CoreOS 创建的开源键值存储系统。它是许多生产级分布式系统的核心组件和 Kubernetes 等项目的数据存储中心。
Java 已经通过在包括 Hadoop 生态系统、Cassandra 数据存储和云基础设施技术栈中的使用而证明了自己是一种流行的分布式系统语言。此外,它仍然是一种非常流行的语言。可以看看在谷歌趋势的统计数据中,Java 仍然占据主导地位:
image.png

就谷歌搜索结果而言,Java 仍然比 Microsoft 的 .Net 甚至 JavaScript 语言更受欢迎

面对着 Java 的流行及其在分布式系统中的普遍使用,我们认为对于 Java 开发来说,etcd 也应该作为后端基础被使用到。jetcd 这个新的 etcd 客户端的出现,将 etcd v3 API 带到了 Java 中。
通过使用 jetcd,Java 应用程序可以使用包装了 etcd 的原生 gRPC 协议的智能 API 来与 etcd 进行纯粹的交互。该 API 提供了仅在 etcd 上可用的表达性分布式特性。更重要的是,通过直接支持更多的语言,使用新的使用模式更容易为 etcd 编写新的应用程序,从而帮助 etcd 变得更加稳定和可靠。

初级入门

你可以通过构建并运行一个名为 jetcdctl 的小例子程序来试用 jetcd,该程序使用了 jetcd 去访问 etcd。对于更进一步的 jetcd 项目来说,jetcdctl 示例也是一个很好的起点。要继续学习,你还需要同时安装 Git 和 Java。
首先,克隆 jetcd 库来获取 jetcd 源码,然后使用 Maven 来构建 jetcd-simple-ctl 吧:

$ git clone https://github.com/coreos/jetcd.git
$ cd jetcd/jetcd-examples/jetcd-simple-ctl
$ ./mvnw clean package

构建并准备好运行 jetcdctl 之后,下载一个 etcd 发行版并在本地启动一个 etcd 服务。(译者注:若以下 “go get” 命令无法正常运行,可以参考这里的资料):

# build with “go get github.com/coreos/etcd/cmd/etcd”
$ etcd &

接下来,使用 jetcdctl 将 123 写入 abc,与本地 etcd 服务器进行通信:

$ java -jar target/jetcdctl.jar put abc 123
21:39:06.126|INFO |CommandPut - OK

你可以通过读取 abc 来确认写入 etcd 的 put 命令的正确性:

$ java -jar target/jetcdctl.jar get abc 21:41:00.265|INFO |CommandGet - abc 21:41:00.267|INFO |CommandGet - 123

我们已经通过 get 和 put keys 演示了 jetcd 的基本功能。现在,让我们进一步研究如何在代码中使用 jetcd 吧。

更好的 watches(观察)特性

jetcd API 可以方便地管理 etcd 的底层 gRPC 协议。一个例子是 streaming key 事件,其中客户端观察 key,etcd 服务端不断地往客户端发回更新信息。jetcd 客户端管理着一个低级别的 gRPC 流,用来优雅地处理断开连接,并向用户呈现一个无缝的事件流。
如果 jetcd 应用程序希望接收到一个 key 的所有更新,它将使用 watch API 来创建一个 Watcher:

Watcher watch(ByteSequence key)

Watcher 的 listen 方法从 etcd 中读取 WatchResponse 消息。每个 WatchResponse 包含被监视 key 上的最新事件序列。如果没有任何事件,则 listen 被阻塞,直到有更新为止。listen 方法是可靠的;它不会在调用之间删除任何事件,即使在断开连接的情况下:

WatchResponse listen() throws InterruptedException

总之,客户端创建一个 Watcher,然后使用 listen 来等待事件。下面是在 key abc 上进行观察的代码,打印观察到的 key 和 value,直到 listen 抛出异常:总之,客户端创建一个 Watcher,然后使用 listen 来等待事件。下面是观察 key abc 的代码,打印 key 和 value,直到 listen 抛出异常:

Client client = Client.builder().endpoints(“http://127.0.0.1:2379).build();
Watcher watcher = client.getWatchClient().watch(ByteSequence.fromString("abc"));
while (true) {
    for (WatchEvent event : watcher.listen().getEvents()) {
        KeyValue kv = event.getKeyValue();
        System.out.println(event.getEventType());
        System.out.println(kv.getKey().toStringUtf8());
        System.out.println(kv.getValue().toStringUtf8());
    }
}

将此特性与 Apache 基金会中与 etcd 对标的 ZooKeeper 进行比较。从 ZooKeeper 3.4.10 开始,watch 就已经是一次性触发器,这意味着一旦收到一个 watch 事件,您必须设置一个新的 watch,以便在将来发生更改时得到通知。要传输密钥事件,可会断必须与集群联系,为每个新事件注册一个新的观察者。
要在 key 更新时连续打印 key 的内容,ZooKeeper 应用程序首先创建一个 Watcher 来侦听 WatchedEvent 消息。观察程序实现了一个事件回调方法 process,当 key 发生更改时就会调用该方法。要在事件中注册兴趣,观察程序需要添加到 exists 方法中,该方法获取 key 的元数据(如果有的话)。当 key 发生变化时,观察者的 process 方法就会调用 getData 来检索 key 的值,然后再次注册相同的观察者来接收未来的更改,如下所示:

key = “/abc”;
Watcher w = new Watcher() {
  public void process(WatchedEvent event) {
    try {
      System.out.println(event.getType());
      System.out.println(event.getPath());
      if (event.getType() != EventType.NodeDeleted) {
        System.out.println(new String(zk.getData(event.getPath(), false, null)));
      }
      zk.exists(key, this);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
};
zk.exists(key, w);

与 jetcd 示例不同,ZooKeeper 代码不能保证它观察所有更改,因为在监视程序接收事件和发送请求以获取新监视之间存在延迟。例如,在执行 process 和调用 exists 以注册新监视程序之间发生了一个事件。由于没有注册任何观察程序,因此该事件永远不会被触发,并且会丢失。
即使假设所有事件都已触发,代码仍然可能破坏事件流。没有 etcd 提供的多版本并发控制,就无法访问历史 key。如果 key value 在接收事件和获取数据之间发生了变化,代码将打印出最新的值,而不是与 watch 事件关联的值。更糟的是,事件没有附带修订信息;无法确定 key 是来自事件还是来自 future 返回。

v0.0.1 版本以及未来计划

从 v0.0.1 开始,jetcd 支持大多数应用程序需要的键值存储。这些原语可以作为复杂模式(如分布式队列、barriers 等)的构建块。在未来,jetcd 将能够使用 etcd 的本地锁和领导人选举 rpc 进行集群范围的标准化分布式协调。
jetcd 设计目的是易于使用,同时还能够利用 etcd 的先进功能。它是开源的,并且正在活跃开发中,欢迎社区的贡献和反馈。我们可以在 GitHub 上找到它,地址是github.com/coreos/jetc…。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
数据采集 自然语言处理 Java
Java新提案,最终还是靠近C#了
Java新提案,最终还是靠近C#了
53 0
Java新提案,最终还是靠近C#了
|
Java C++
【Java】抽象类_接口_最终类
【Java】抽象类_接口_最终类
131 0
【Java】抽象类_接口_最终类
|
存储 Java 程序员
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
🍅程序员小王的博客:程序员小王的博客 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 🍅java自学的学习路线:java自学的学习路线
363 0
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
Java 在内部类中访问变量需要宣布为最终
Java 在内部类中访问变量需要宣布为最终
|
Java
java学习第八天笔记-方法168-两个数组对象练习最终
java学习第八天笔记-方法168-两个数组对象练习最终
60 0
java学习第八天笔记-方法168-两个数组对象练习最终
|
存储 Java
一文理解原码、反码、补码,探究JAVA代码最终以何种方式保存
一文理解原码、反码、补码,探究JAVA代码最终以何种方式保存
221 0
|
Java
Java中的final关键字(最终结果)
给这个修饰的进行"写死"。防止别人进行二次修改。拒绝别人修改的规则
71 0
|
存储 算法 Java
Java初学者作业——编写JAVA程序,计算跳水运动员本次动作的最终得分。
Java初学者作业——编写JAVA程序,计算跳水运动员本次动作的最终得分。
534 0
Java初学者作业——编写JAVA程序,计算跳水运动员本次动作的最终得分。
|
存储 Java
Java初学者作业——编写JAVA程序,要求输入技术部门5位员工的理论成绩和实操成绩,计算并输出各位员工的最终评测成绩。
Java初学者作业——编写JAVA程序,要求输入技术部门5位员工的理论成绩和实操成绩,计算并输出各位员工的最终评测成绩。
263 0
Java初学者作业——编写JAVA程序,要求输入技术部门5位员工的理论成绩和实操成绩,计算并输出各位员工的最终评测成绩。
|
安全 Java 程序员
Java 反射最终篇 - Mock 对象和桩(下)
Java 反射最终篇 - Mock 对象和桩(下)
171 0
Java 反射最终篇 - Mock 对象和桩(下)