资讯详情

云原生微服务治理etcd应用实战

我曾在美团等一线互联网公司工作,现为源图信息有限公司架构负责人,负责公司整体系统架构。我也是拉钩教育专栏《Go 微服务实战 38 作者,这是我的第一个 2 个专栏。

我很早就关注了微服务架构,对云原生、微服务、容器化、分布式中间件等进行了深入研究,并在此基础上带领公司团队从零开始 Kubernetes 搭建更完善的开发、运维部署和容器调度平台。目前公司的整体业务都是基于这个架构运营的,这让我在 etcd 在服务注册和发现中心、分布式键值存储等场景中积累了大量的实践经验。

etcd 落地于分布式架构和云原时代

互联网应用经历了从早期单一架构到垂直架构再到分布式架构的技术发展过程。随着业务系统的不断发展和变化,用户体积和性能要求远远超出了传统行业的能力,越来越多的公司进入了分布式和云本地架构的行列,

然而,分布式架构系统面临着部署复杂、响应时间慢、复杂、响应时间慢、操作和维护复杂等,其中最基本的是多个节点之间的数据共享问题。面对这个问题,您可以选择实现可靠的共享存储来同步信息,或可靠的共享存储服务。

可靠的共享存储服务,etcd 这是一个很好的选择。etcd 使用分布式存储中间件 Go 并通过语言编写 Raft 处理一致性算法,保证分布式一致性,

而且作为分布式、可靠的键值存储组件,etcd 与微服务架构中常用的服务注册和发现中心相比, ZooKeeper 部署更简单,数据持久,支持 SSL 客户端安全认证的独特优势。

此外,由于 etcd 它涉及数据一致性和多版本并发控制watch 监控、磁盘 IO 读写等知识点,深入学习 etcd 能帮助我们

除分布式架构的应用外,etcd 它仍然是目前非常流行的云原生存储组件,它来自 2018 年底加入孵化项目 CNCF(云原生计算基金会),并于 2020 年 11 月成功毕业。

我们都知道,上 “云” 这个过程一定是曲折的。以我所在的在线教育行业为例,从原有的单体业务改造到逐步替换成云原生架构,其中花费的人力、时间成本都很大,这不仅与实际的业务复杂度、升级的决心有关,更关乎技术复杂度,在线课程直播场景甚至要求架构实现高性能、高并发和高可用性,这些都远远超出传统单体应用的设计和开发要求。

etcd 作为云原生架构的重要基本组成部分,通过各种微服务 etcd 确保调用的可用性和正确性。其成功在许多其他知名项目(包括 等)也依赖 etcd 可以看到可靠的分布式数据存储。

IBM 高级软件工程师兼开放技术 etcd 维护者 Sahdev Zala 也指出:“etcd 提供分布式键 - 值存储起着关键作用。它的存储功能不仅可用性高,而且可以满足大规模的需求 Kubernetes 集群提出的强一致性要求。

,因此,越来越多的公司在系统服务中引入,甚至取代原始的类似组件(如 ZooKeeper、Consul、Eureka 等等。etcd 已被阿里巴巴、亚马逊、百度等多家公司用于生产Google 等。

为什么会有这门课?

当然,作为分布式开发从业者,在学习和实践分布式组件的过程中,你可能会遇到各种各样的问题:

不要担心这些问题,就像我前面提到的,etcd 它是分布式和云原生架构下的重要组成部分 etcd 在此基础上学习分布式,可以帮助您快速熟悉分布式系统的一些细节和原理。

如今,企业对分布式开发人才的需求越来越大。通过搜索招聘网站,您可以了解到这些职位是稀缺的高薪职位。正因为如此,掌握相关的分布式组件和技能将为您在日常工作和面试推广评估中加分,甚至有助于提高您合理设计业务系统架构的能力。

(数据来自拉钩网招聘)

etcd 作为一个,它可以为整个分布式集群存储一些关键数据,以帮助分布式集群的正常运行。如何正确部署和运行维护 etcd 集群,并对集群进行优化,以及在开发层面如何正确调用 etcd 客户端 API 实现一致性存储等功能越来越重要。

所以我和拉钩教育平台合作了这门课,希望能带你深入学习 etcd 原则与实战。

课程设计

本课程从基础知识点到底层原理进行了全面深入的介绍,分为 3 合计模块 21 讲。

:介绍 etcd 是一款什么样的组件、etcd 相关特点、应用场景、单机和集群部署也包括使用客户命令行工具,以及 etcd 通信加密 TLS。初步了解 etcd 这些基本使用可以为你以后的学习打下基础。

此外,我还将介绍动态重配置、参数调整、故障恢复和集群 etcd 网关模式等。为了在生产环境中高度可用,不可能单机部署 etcd 因此,这样的重要组件 etcd 集群的部署和应用非常重要。通过高级学习 etcd 这些知识点会使我们的系统更强大。

:介绍 etcd 重点介绍工作方法和内部实现原理 etcd 的 etcd-raft 模块、WAL 日志和快照备份,多版本控制 MVCC、backend 存储、实现事务、watch 和 lease 机制等,最后梳理 etcd server 以及如何处理客户端请求。

通过学习这个模块,你可以从原理层面深入理解 etcd 工作机制和整体结构也会对你有所帮助

:在掌握了 etcd 在应用实践中,我会带你学习相关知识点 etcd ClientV3 具体应用包括如何基于 etcd 实现分布式锁,etcd 选举在统一定时任务中的应用,以及如何在微服务中集成 etcd 作为服务注册和发现中心。最后,我会带你去分析Kubernetes 中如何基于 etcd 完成容器的调度。

讲师寄语

目前,云原生架构已逐渐成为系统架构的主流,因为它可以大大提高产品的开发迭代效率,降低运维和硬件成本,企业是否应该去 “云” 不再是难题,而是必然趋势。etcd 作为分布式架构下的优秀组成部分,在云原时代更加辉煌,成为云原时代 Kubernetes 平台默认注册和发现容器组件。

如果您有分布式基础,并且正在从事分布式系统开发,本专栏的内容非常适合您学习;对于微服务开发者、分布式系统架构师和运维人员,特别是基于 etcd 对于进行相关实践的工程师,你将从工作中受益;对云原生架构感兴趣的学生也可以了解分布式系统的原理和实践。

我希望你过 etcd 学习分布式组件 道,掌握学习的方式将在你随后的自我完善中发挥长期的价值。无论是在未来的面试还是开发中,你都可以将原则和应用结合起来,充分反映个人的核心竞争力,更好地实现个人价值。

教学相长,希望在 etcd 在分布式发展的学习和成长过程中,我们共同进步!我在留言区等你。

近年来,云原生越来越受欢迎,你可以在各种会议或博客的标题中看到 “云原生” 这次我们要学的字样 etcd 它也是云原生架构的重要基本组成部分,因为 etcd 项目是 Kubernetes 目前,许多项目依赖于内部的关键组件 etcd 存储可靠的分布式数据。

etcd 是 CoreOS 团队于 2013 年 6 2018年月发起的开源项目 年底正式加入云原计算基金会(CNCF)。etcd 组件基于 Go 语言实现的最新版本是 V3.4.9。

为什么需要 etcd

在具体讲解 etcd 先说分布式系统。

从本质上讲,云微服务的应用属于分布式系统的实践。在分布式环境中,由于网络的复杂性、不确定性和节点故障,会出现一系列问题。最常见和最大的困难是问题是,多个服务实例本身的数据或获得的数据是不同的。因此,我们需要建立一个基于一致性的存储组件的可靠分布式系统。

分布式中的 CAP 理论

CAP 原理是描述分布式系统下节点数据同步的基本定理,分别指 ,这三个要素最多只能同时实现两点,不能三者兼顾。

基于分布式系统的基本特质,P(分区容错性)是必须要满足的,所以接下来需要考虑满足 C(一致性)还是 A(可用性)。

在类似银行之类对金额数据要求强一致性的系统中,要优先考虑满足数据一致性;而在大众网页之类的系统中,用户对网页版本的新旧不会有特别的要求,在这种场景下服务可用性会高于数据一致性。

了解了分布式系统中的问题,接下来让我们结合官网中的定义,看看为什么在分布式系统中需要 etcd?

etcd 是什么

根据 etcd 官网的介绍,我找到了如下定义:

A highly-available key value store for shared configuration and service discovery. 即一个用于配置共享和服务发现的键值存储系统。

从定义上你也可以发现,etcd 归根结底是一个存储组件,且可以实现配置共享和服务发现。

在分布式系统中,各种服务配置信息的管理共享和服务发现是一个很基本也是很重要的问题,无论你调用服务还是调度容器,都需要知道对应的服务实例和容器节点地址信息。etcd 就是这样一款

。服务端将配置信息存储于 etcd,客户端通过 etcd 得到服务配置信息,etcd 监听配置信息的改变,发现改变通知客户端。

而 etcd 满足 CAP 理论中的 CP(一致性和分区容错性) 指标,由此我们知道,etcd 解决了分布式系统中一致性存储的问题。

etcd 中常用的术语

为了我们接下来更好地学习 etcd,我在这里给你列举了常用的 etcd 术语,尽快熟悉它们也会对接下来的学习有所助益。

下面我们具体了解一下 etcd 的相关特性、架构和使用场景。

etcd 的特性

etcd 可以用来构建高可用的分布式键值数据库,总结来说有如下特点。

  • :etcd 的安装简单,且为用户提供了 HTTP API,使用起来也很简单。

  • :etcd 的基本功能,数据分层存储在文件目录中,类似于我们日常使用的文件系统。

  • :Watch 指定的键、前缀目录的更改,并对更改时间进行通知。

  • :支持 SSL 证书验证。

  • :etcd 单实例可以支持 2K/s 读操作,官方也有提供基准测试脚本。

  • :基于 Raft 共识算法,实现分布式系统内部数据存储、服务调用的一致性和高可用性。

etcd 是一个实现了分布式一致性键值对存储的中间件,支持跨平台,拥有活跃用户的技术社区。etcd 集群中的节点基于 Raft 算法进行通信,Raft 算法保证了微服务实例或机器集群所访问的数据的可靠一致性。

在分布式系统或者 Kubernetes 集群中,etcd 可以。不管是简单应用程序,还是复杂的容器集群,都可以很方便地从 etcd 中读取数据,满足了各种场景的需求。

etcd 的应用场景

etcd 在稳定性、可靠性和可伸缩性上表现极佳,同时也为云原生应用系统提供了协调机制。etcd 经常用于服务注册与发现的场景,此外还有键值对存储、消息发布与订阅、分布式锁等场景。

etcd 是一个用于的组件,存储是 etcd 最基本的功能,其他应用场景都建立在 etcd 的可靠存储上。比如 Kubernetes 将一些元数据存储在 etcd 中,将存储状态数据的复杂工作交给 etcd,Kubernetes 自身的功能和架构就能更加稳定。

etcd 基于 Raft 算法,能够有力地保证分布式场景中的一致性。各个服务启动时注册到 etcd 上,同时为这些服务配置键的 TTL 时间。注册到 etcd 上面的各个服务实例通过心跳的方式定期续租,实现服务实例的状态监控。

在分布式系统中,服务之间还可以通过消息通信,即消息的发布与订阅,如下图所示:

消息发布与订阅流程图

通过构建 etcd 消息中间件,服务提供者发布对应主题的消息,消费者则订阅他们关心的主题,一旦对应的主题有消息发布,就会产生订阅事件,消息中间件就会通知该主题所有的订阅者。

分布式系统中涉及多个服务实例,存在跨进程之间资源调用,对于资源的协调分配,单体架构中的锁已经无法满足需要,需要引入分布式锁的概念。etcd 基于 Raft 算法,实现分布式集群的一致性,存储到 etcd 集群中的值必然是全局一致的,因此基于 etcd 很容易实现分布式锁。

etcd 的核心架构

etcd 作为一个如此重要的部件,我们只有深入理解其架构设计才能更好地学习。下面还是先来看看 etcd 总体的架构图。

etcd 总体架构图

从上图可知,etcd 有 etcd Server、gRPC Server、存储相关的 MVCC 、Snapshot、WAL,以及 Raft 模块。

其中:

  • etcd Server 用于对外接收和处理客户端的请求;

  • gRPC Server 则是 etcd 与其他 etcd 节点之间的通信和信息同步;

  • MVCC,即多版本控制,etcd 的存储模块,键值对的每一次操作行为都会被记录存储,这些数据底层存储在 BoltDB 数据库中;

  • WAL,预写式日志,etcd 中的数据提交前都会记录到日志;

  • Snapshot 快照,以防 WAL 日志过多,用于存储某一时刻 etcd 的所有数据;

  • Snapshot 和 WAL 相结合,etcd 可以有效地进行数据存储和节点故障恢复等操作。

虽然 etcd 内部实现机制复杂,但对外提供了简单的 API 接口,方便客户端调用。我们可以通过 操作和访问 etcd 中的数据,或者通过 接口直接访问 etcd。

etcd 中的数据结构很简单,它的数据存储其实就是键值对的有序映射。etcd 还提供了一种键值对监测机制,即 Watch 机制,客户端通过订阅相关的键值对,获取其更改的事件信息。Watch 机制实时获取 etcd 中的增量数据更新,使数据与 etcd 同步。

etcd 目前有 V2.x 和 V3.x 两个大版本。etcd V2 和 V3 是在底层使用同一套 Raft 算法的两个独立应用,但相互之间实现原理和使用方法上差别很大,接口不一样、存储不一样,两个版本的数据互相隔离。

至于由 etcd V2 升级到 etcd V3 的情况,原有数据只能通过 etcd V2 接口访问,V3 接口创建的数据只能通过新的 V3 的接口访问。我们的专栏重点讲解

小结

这一讲我主要介绍了 etcd 相关的概念。关于 etcd 你需要记住以下三点:

  • etcd 是云原生架构中的存储基石,可以有效保证存储数据的一致性和可靠性;

  • etcd 内部实现机制复杂,但是对外提供了简单直接的 API 接口;

  • 使用 etcd 的常见分布式场景包括键值对存储、服务注册与发现、消息订阅与发布、分布式锁等。

下一讲我将开始讲解 etcd 的安装部署,手把手教你玩转 etcd 搭建。

在学习今天的内容之前,你有没有使用过 etcd,你理解的 etcd 功能是什么样的?欢迎你在留言区和我分享。

这一讲我们将一同学习 etcd 部署的几种方式,以及如何进行 TLS 加密实践,以保证 etcd 的通信安全。

etcd 单机安装部署

etcd 的安装有多种方式,这里我以 CentOS 7 为例,可以通过yum install etcd进行安装。然而通过系统工具安装的 etcd 版本比较滞后,如果需要安装最新版本的 etcd ,我们可以通过二进制包、源码编译以及 Docker 容器安装。

二进制安装

目前最新的 etcd API 版本为 v3.4,我们基于 3.4.4 版本进行实践,API 版本与最新版保持一致,在 CentOS 7 上面使用如下脚本进行安装:

ETCD_VER=v3.4.4


GITHUB_URL=https:


DOWNLOAD_URL=${GITHUB_URL}


rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz


rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test


curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz


tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1


rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz


/tmp/etcd-download-test/etcd --version


/tmp/etcd-download-test/etcdctl version

下载可能比较慢,执行后,查看 etcd 版本的结果如下:

etcd Version: 3.4.4


Git SHA: e784ba73c


Go Version: go1.12.12


Go OS/Arch: linux/amd64

根据上面的执行结果可以看到,我们在 Linux 上安装成功,macOS 的二进制安装也类似,这里不重复演示了。关于 Windows 系统的安装比较简单,下载好安装包后,直接执行。其中 etcd.exe 是服务端,etcdctl.exe 是客户端,如下图所示:

源码安装

使用源码安装,首先你需要确保本地的 Go 语言环境。如未安装,请参考 https://golang.org/doc/install 安装 Go 语言环境。我们需要 Go 版本为 1.13+,来构建最新版本的 etcd。如果你想尝试最新版本,也可以从 master 分支构建 etcd。

首先查看一下我们本地的 Go 版本:

$ go version


Go version go1.13.6 linux/amd64

经检测,本地的 Go 版本满足要求。将制定版本的 etcd 项目 clone 到本地之后,在项目文件夹构建 etcd。构建好之后,执行测试命令,确保 etcd 编译安装成功:

$ ./etcdctl version


etcdctl version: 3.4.4


API version: 3.4

经过上述步骤,我们已经通过源码编译成功安装 etcd。

除此之外,还可以使用 Docker 容器安装,这种方式更为简单,但这种方式有一个弊端:启动时会将 etcd 的端口暴露出来。

etcd 集群安装部署

刚刚我们介绍了 etcd 的单机安装,但是。下面我们看看如何进行 etcd 集群部署。

引导 etcd 集群的启动有以下三种方式:

  • 静态启动

  • etcd 动态发现

  • DNS 发现

其中静态启动 etcd 集群的方式要求每个成员都知道集群中的其他成员。然而很多场景中,群集成员的 IP 可能未知。因此需要借助发现服务引导 etcd 群集启动。下面我们将会分别介绍这几种方式。

静态方式启动 etcd 集群

如果我们想在一台机器上实践 etcd 集群的搭建,可以通过 goreman 工具。

goreman 是一个 Go 语言编写的多进程管理工具,是对 Ruby 下广泛使用的 Foreman 的重写。下面我们使用 goreman 来演示在一台物理机上面以静态方式启动 etcd 集群。

前面我们已经确认过 Go 语言的安装环境,现在可以直接执行:

go get github.com/mattn/goreman

编译后的文件放在$GOPATH/bin中,$GOPATH/bin目录已经添加到了系统$PATH中,所以我们可以方便地执行命令goreman命令。

下面就是编写 Procfile 脚本,我们启动三个 etcd,具体对应如下:

Procfile 脚本中 infra1 启动命令如下:

etcd1: etcd --name infra1 --listen-client-urls http:

infra2 和 infra3 的启动命令类似。下面我们看一下其中各配置项的说明。

  • –name:etcd 集群中的节点名,这里可以随意,方便区分且不重复即可。

  • –listen-client-urls:监听用于客户端通信的 url,同样可以监听多个。

  • –advertise-client-urls:建议使用的客户端通信 url,该值用于 etcd 代理或 etcd 成员与 etcd 节点通信。

  • –listen-peer-urls:监听用于节点之间通信的 url,可监听多个,集群内部将通过这些 url 进行数据交互 (如选举、数据同步等)。

  • –initial-advertise-peer-urls:建议用于节点之间通信的 url,节点间将以该值进行通信。

  • –initial-cluster-token: etcd-cluster-1,节点的 token 值,设置该值后集群将生成唯一 ID,并为每个节点也生成唯一 ID。当使用相同配置文件再启动一个集群时,只要该 token 值不一样,etcd 集群就不会相互影响。

  • –initial-cluster:集群中所有的 initial-advertise-peer-urls 的合集。

  • –initial-cluster-state:new,新建集群的标志。

注意上面的脚本,。下面我们使用goreman命令启动 etcd 集群:

goreman -f /opt/procfile start

启动完成后查看集群内的成员:

$ etcdctl --endpoints=http:


8211f1d0f64f3269, started, infra1, http:


91bc3c398fb3c146, started, infra2, http:


fd422379fda50e48, started, infra3, http:

现在我们的 etcd 集群已经搭建成功。需要注意的是:

动态发现启动 etcd 集群

Discovery Service,即发现服务,帮助新的 etcd 成员使用共享 URL 在集群引导阶段发现所有其他成员。

Discovery Service 使用已有的 etcd 集群来协调新集群的启动,主要操作如下:

  • 首先,所有新成员都与发现服务交互,并帮助生成预期的成员列表;

  • 之后,每个新成员使用此列表引导其服务器,该列表执行与--initial-cluster标志相同的功能,即设置所有集群的成员信息。

我们的实验中启动三个 etcd 实例,具体对应如下:

下面就开始以动态发现的方式来启动 etcd 集群,具体步骤如下。

。该令牌将用于键空间中的唯一前缀,比较简单的方法是使用 uuidgen 生成 UUID:

获取令牌时,必须指定群集大小。

我们需要把该 url 作为--discovery参数来启动 etcd,节点会自动使用该路径对应的目录进行 etcd 的服务注册与发现。

当我们本地没有可用的 etcd 集群,etcd 官网提供了一个可以公网访问的 etcd 存储地址。你可以通过如下命令得到 etcd 服务的目录,并把它作为--discovery参数使用。

公共发现服务discovery.etcd.io以相同的方式工作,但是有一层修饰,在此之上仍然使用 etcd 群集作为数据存储。

etcd 发现模式下,启动 etcd 的命令如下:

# etcd1 启动


$ /opt/etcd/bin/etcd  --name etcd1 --initial-advertise-peer-urls http://192.168.202.128:2380 \


  --listen-peer-urls http://192.168.202.128:2380 \


  --data-dir /opt/etcd/data \


  --listen-client-urls http://192.168.202.128:2379,http://127.0.0.1:2379 \


  --advertise-client-urls http://192.168.202.128:2379 \


  --discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de

etcd2 和 etcd3 启动类似,替换 listen-peer-urls 和 advertise-client-urls 即可。需要注意的是:--discovery就失去了作用。当需要增加节点时,需要使用 etcdctl 进行操作。

为了安全,每次启动新 etcd 集群时,都会使用新的 discovery token 进行注册。当出现初始化启动的节点超过了指定的数量时,多余的节点会自动转化为 Proxy 模式的 etcd(在后面课时会详细介绍)。

集群启动后,进行验证,我们看一下集群节点的健康状态:

$ /opt/etcd/bin/etcdctl  --endpoints="http://192.168.202.128:2379,http://192.168.202.129:2379,http://192.168.202.130:2379"  endpoint  health


# 结果如下


    http://192.168.202.128:2379 is healthy: successfully committed proposal: took = 3.157068ms


    http://192.168.202.130:2379 is healthy: successfully committed proposal: took = 3.300984ms


    http://192.168.202.129:2379 is healthy: successfully committed proposal: took = 3.263923ms

可以看到,集群中的三个节点都是健康的正常状态,可以说明以动态发现方式启动集群成功。

除此之外,。使用 DNSmasq 创建 DNS 服务,实际上是利用 DNS 的 SRV 记录不断轮训查询实现,DNS SRV 是 DNS 数据库中支持的一种资源记录的类型,它记录了计算机与所提供服务信息的对应关系。

至此,我们就介绍完了 etcd 安装部署的两种方式,对于可靠的系统来说,还需要考虑 etcd 集群通信的安全性,为我们的数据安全增加防护。

etcd 通信安全

etcd 支持通过 TLS 协议进行的加密通信,TLS 通道可用于对等体(指 etcd 集群中的服务实例)之间的加密内部群集通信以及加密的客户端流量。这一节我们看一下客户端 TLS 设置群集的实现。

想要实现数据 HTTPS 加密协议访问、保障数据的安全,就需要 SSL 证书,TLS 是 SSL 与 HTTPS 安全传输层协议名称。

进行 TLS 加密实践

为了进行实践,我们将安装一些实用的命令行工具,这包括 CFSSL 、cfssljson。

CFSSL 是 CloudFlare 的 PKI/TLS 加密利器。它既是命令行工具,也可以用于签名、验证和捆绑 TLS 证书的 HTTP API 服务器,需要 Go 1.12+ 版本才能构建。

$ ls ~/Downloads/cfssl


cfssl-certinfo_1.4.1_linux_amd64 cfssl_1.4.1_linux_amd64          cfssljson_1.4.1_linux_amd64


chmod +x cfssl_1.4.1_linux_amd64 cfssljson_1.4.1_linux_amd64 cfssl-certinfo_1.4.1_linux_amd64


mv cfssl_1.4.1_linux_amd64 /usr/local/bin/cfssl


mv cfssljson_1.4.1_linux_amd64 /usr/local/bin/cfssljson


mv cfssl-certinfo_1.4.1_linux_amd64 /usr/bin/cfssl-certinfo

安装完成后,查看版本信息如下所示:

$ cfssl version


Version: 1.4.1


Runtime: go1.12.12

我们将使用 CloudFlare’s PKI 工具 CFSSL 来配置 PKI 安全策略,然后用它创建 Certificate Authority(CA,即证书机构),并为 etcd 创建 TLS 证书。

首先创建 SSL 配置目录:

mkdir /opt/etcd/{bin,cfg,ssl} -p


cd /opt/etcd/ssl/

接下来完善 etcd CA 配置,写入 ca-config.json 如下的配置:

cat << EOF | tee ca-config.json


{


"signing": {


"default": {


"expiry": "87600h"


    },


"profiles": {


"etcd": {


"expiry": "87600h",


"usages": [


"signing",


"key encipherment",


"server auth",


"client auth"


        ]


      }


    }


  }


}


EOF

生成获取 etcd ca 证书,需要证书签名的请求文件,因此在 ca-csr.json 写入如下的配置:

cat << EOF | tee ca-csr.json


{


"CN": "etcd CA",


"key": {


"algo": "rsa",


"size": 2048


    },


"names": [


        {


"C": "CN",


"L": "Shanghai",


"ST": "Shanghai"


        }


    ]


}


EOF

根据上面的配置,生成 CA 凭证和私钥:

$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca

生成 etcd server 证书,写入 server-csr.json 如下的配置:

cat << EOF | tee server-csr.json


{


"CN": "etcd",


"hosts": [


"192.168.202.128",


"192.168.202.129",


"192.168.202.130"


    ],


"key": {


"algo": "rsa",


"size": 2048


    },


"names": [


        {


"C": "CN",


"L": "Beijing",


"ST": "Beijing"


        }


    ]


}


EOF

最后就可以生成 server 证书了:

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd server-csr.json | cfssljson -bare server

启动 etcd 集群,配置如下:

#etcd1 启动


$ /opt/etcd/bin/etcd --name etcd1 --initial-advertise-peer-urls https://192.168.202.128:2380 \


     --listen-peer-urls https://192.168.202.128:2380 \


     --listen-client-urls https://192.168.202.128:2379,https://127.0.0.1:2379 \


     --advertise-client-urls https://192.168.202.128:2379 \


     --initial-cluster-token etcd-cluster-1 \


     --initial-cluster etcd1=https://192.168.202.128:2380, etcd2=https://192.168.202.129:2380, etcd3=https://192.168.202.130:2380 \


     --initial-cluster-state new \


     --client-cert-auth --trusted-ca-file=/opt/etcd/ssl/ca.pem \


     --cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \


     --peer-client-cert-auth --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \


     --peer-cert-file=/opt/etcd/ssl/server.pem --peer-key-file=/opt/etcd/ssl/server-key.pem

etcd2 和 etcd3 启动类似,。通过三台服务器的控制台可以知道,集群已经成功建立。

下面我们进行验证:

$ /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.202.128:2379,https://192.168.202.129:2379,https://192.168.202.130:2379"  endpoint health


# 输出如下:


https://192.168.202.129:2379 is healthy: successfully committed proposal: took = 9.492956ms


https://192.168.202.130:2379 is healthy: successfully committed proposal: took = 12.805109ms


https://192.168.202.128:2379 is healthy: successfully committed proposal: took = 13.036091ms

查看三个节点的健康状况,endpoint health,输出的结果符合我们的预期。

经过 TLS 加密的 etcd 集群,在进行操作时,需要加上认证相关的信息。

如果集群需要加密的通信但不需要经过身份验证的连接,可以将 etcd 配置为自动生成其密钥。在初始化时,每个成员都基于其通告的 IP 地址和主机创建自己的密钥集。

在每台机器上,etcd 将使用以下标志启动:

$ etcd --name etcd1 --initial-advertise-peer-urls https:


  --listen-peer-urls https:


  --listen-client-urls https:


  --advertise-client-urls https:


  --initial-cluster-token etcd-cluster-1 \


  --initial-cluster infra0=https:


  --initial-cluster-state new \


  --auto-tls \


  --peer-auto-tls

由于自动签发证书并不能认证身份,直接 curl 会返回错误,

小结

这一讲我们主要介绍了 etcd 的安装部署方式,包括单机和集群的部署。为了高可用,在生产环境中我们一般选择使用集群的方式部署 etcd。在集群部署的时候,有静态和动态两种方式发现集群中的成员。静态的方式是直接在启动时指定各个成员的地址,但在实际环境中,集群成员的 IP 可能不会提前知道,这时候就需要采用动态发现的机制。

Discovery Service 用于生成集群的发现令牌,需要注意的是,。一个发现令牌只能代表一个 etcd 集群,只要此令牌上的发现协议启动,即使它中途失败,也不能用于引导另一个 etcd 集群。我在这一讲最后也介绍了 etcd 集群通过 TLS 协议进行的加密通信,来保证 etcd 通信的安全。

下一讲我们将学习如何使用 etcdctl 客户端与 etcd 服务端进行交互,以及操作 etcd 服务端。有任何疑问欢迎在留言区和我互动,我们下一讲再见!

上一讲我们介绍了 etcd 的几种安装部署方式以及 TLS 安全加密等知识点。安装好 etcd 后,我们将开始体验如何使用 etcd。这一讲,我将会基于 etcd 自带的客户端工具——etcdctl 来演示 etcd 常用的一些操作,帮助你快速入手 etcd。

etcdctl 客户端

etcdctl 是一个命令行客户端,便于我们进行,我们刚开始熟悉 etcd 功能时可以通过 etdctl 客户端熟悉相关操作。etcdctl 在两个不同的 etcd 版本(v2 和 v3)下的功能和使用方式也完全不同。一般通过如下方式来指定使用 etcd 的版本:

export ETCDCTL_API=2


export ETCDCTL_API=3

我们的专栏课程主要讲解 API 3。etcd 项目二进制发行包中已经包含了 etcdctl 工具,通过 etcd 安装包中的 etcdctl 可执行文件可以进行调用。下面我们先来看看 etcd 的常用命令有哪些,并进行实践应用。

常用命令介绍

我们首先来看下 etcdctl 支持哪些命令,通过etcdctl -h命令查看:

$ etcdctl -h


NAME:


	etcdctl - A simple command line client for etcd3.


USAGE:


	etcdctl [flags]


VERSION:


3.4.4


API VERSION:


3.4

COMMANDS:

OPTIONS:

etcdctl 支持的命令大体上分为两类。其中数据库的操作命令是最常用的命令,我们将在下面具体介绍。其他的命令如用户、角色、授权、认证相关,你可以根据语法自己尝试一下。

数据库操作

数据库操作基本围绕着对键值和目录的 CRUD 操作(即增删改查),及其对应的生命周期管理。我们上手这些操作其实很方便,因为这些操作是符合 REST 风格的一套 API 操作。

etcd 在键的组织上采用了类似文件系统中目录的概念,即,我们指定的键可以作为键名,如:testkey,实际上,此时键值对放于根目录 / 下面。我们也可以为键的存储,如 /cluster/node/key;如果不存在 /cluster/node 目录,则 etcd Server 将会创建相应的目录结构。

下面我们基于键操作、watch、lease 三类分别介绍 etcdctl 的使用与实践。

键操作

键操作包括最常用的增删改查操作,包括 PUT、GET、DELETE 等命令。

。例如:

$ etcdctl put /test/foo1 "Hello world"


$ etcdctl put /test/foo2 "Hello world2"


$ etcdctl put /test/foo3 "Hello world3"

成功写入三对键值,/test/foo1、/test/foo2 和 /test/foo3。

。例如获取 /testdir/testkey 对应的值:

$ etcdctl get /testdir/testkey


Hello world

除此之外, etcdctl 的 GET 命令还提供了根据指定的键(key),获取其对应的十六进制格式值,即以十六进制格式返回:

$ etcdctl get /test/foo1 --hex


\x2f\x74\x65\x73\x74\x64\x69\x72\x2f\x74\x65\x73\x74\x6b\x65\x79 #键


\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64 #值

加上--print-value-only可以读取对应的值。十六进制在 etcd 中有多处使用,如 也是十六进制。

GET 范围内的值:

$ etcdctl get /test/foo1 /test/foo3


/test/foo1


Hello world


/test/foo2


Hello world2

可以看到,上述操作获取了大于等于 /test/foo1,且小于 /test/foo3 的键值对。foo3 不在范围之内,因为范围是半开区间 [foo1, foo3),不包含 foo3。

获取某个前缀的所有键值对,通过 --prefix 可以指定前缀:

$ etcdctl get --prefix /test/foo


/test/foo1


Hello world


/test/foo2


Hello world2


/test/foo3


Hello world3

这样就能获取所有以 /test/foo 开头的键值对,当前缀获取的结果过多时,还可以通过 --limit=2 限制获取的数量:

etcdctl get --prefix --limit=2 /test/foo

读取键过往版本的值,应用可能想读取键的被替代的值。

例如,应用可能想。或者,应用可能想,而这些请求可以通过访问键历史记录而来。因为 etcd 集群上键值存储的每个修改都会增加 etcd 集群的全局修订版本,应用可以通过提供旧有的 etcd 修改版本来读取被替代的键。现有如下键值对:

foo = bar         # revision = 2


foo1 = bar2       # revision = 3


foo = bar_new     # revision = 4


foo1 = bar1_new   # revision = 5

以下是访问以前版本 key 的示例:

$ etcdctl get --prefix foo # 访问最新版本的 key


foo


bar_new


foo1


bar1_new


$ etcdctl get --prefix --rev=4 foo # 访问第 4 个版本的 key


foo


bar_new


foo1


bar1


$ etcdctl get --prefix --rev=3 foo #  访问第 3 个版本的 key


foo


bar


foo1


bar1


$ etcdctl get --prefix --rev=2 foo #  访问第 3 个版本的 key


foo


bar


$ etcdctl get --prefix --rev=1 foo #  访问第 1 个版本的 key

应用可能想读取大于等于指定键的 byte 值的键。假设 etcd 集群已经有如下列键:

读取大于等于键 b 的 byte 值的键的命令:

$ etcdctl get --from-key b


b


456


z


789

假设 etcd 集群已经有下列键:

foo = bar


foo1 = bar1


foo3 = bar3


zoo = val


zoo1 = val1


zoo2 = val2


a = 123


b = 456


z = 789

删除键 foo 的命令:

$ etcdctl del foo


1 # 删除了一个键

删除从 foo 到 foo9 范围的键的命令:

$ etcdctl del foo foo9


2 # 删除了两个键

删除键 zoo 并返回被删除的键值对的命令:

$ etcdctl del --prev-kv zoo


1   # 一个键被删除


zoo # 被删除的键


val # 被删除的键的值

删除前缀为 zoo 的键的命令:

$ etcdctl del --prefix zoo


2 # 删除了两个键

删除大于等于键 b 的 byte 值的键的命令:

$ etcdctl del --from-key b


2 # 删除了两个键

watch 键值对的改动

etcd 的 watch 功能是一个常用的功能,我们来看看通过 etcdctl 如何实现 watch 指定的键值对。

watch 监测一个键值的变化,一旦。例如:用户更新 testkey 键值为 Hello watch。

$ etcdctl watch testkey


# 在另外一个终端: etcdctl put testkey Hello watch


testkey


Hello watch

从 foo to foo9 范围内键的命令:

$ etcdctl watch foo foo9


# 在另外一个终端: etcdctl put foo bar


PUT


foo


bar


# 在另外一个终端: etcdctl put foo1 bar1


PUT


foo1


bar1

以 16 进制格式在键 foo 上进行观察的命令:

$ etcdctl watch foo --hex


# 在另外一个终端: etcdctl put foo bar


PUT


\x66\x6f\x6f          # 键


\x62\x61\x72          # 值

观察多个键 foo 和 zoo 的命令:

$ etcdctl watch -i


$ watch foo


$ watch zoo


# 在另外一个终端: etcdctl put foo bar


PUT


foo


bar


# 在另外一个终端: etcdctl put zoo val


PUT


zoo


val

查看 key 的历史改动,应用可能想观察 etcd 中键的历史改动。

例如,应用服务想要获取某个键的所有修改。如果应用客户端一直与 etcd 服务端保持连接,使用 watch 命令就能够实现了。但是当应用或者 etcd 实例出现异常,该键的改动可能发生在出错期间,这样导致了应用客户端没能实时接收这个更新。因此,,为了做到这点,应用客户端可以在观察时指定一个历史修订版本。

首先我们需要完成下述序列的操作:

$ etcdctl put foo bar         # revision = 2


OK


$ etcdctl put foo1 bar1       # revision = 3


OK


$ etcdctl put foo bar_new     # revision = 4


OK


$ etcdctl put foo1 bar1_new   # revision = 5


OK

观察历史改动:

# 从修订版本 2 开始观察键 `foo` 的改动


$ etcdctl watch --rev=2 foo


PUT


foo


bar


PUT


foo


bar_new

从上一次历史修改开始观察:

# 在键 `foo` 上观察变更并返回被修改的值和上个修订版本的值


$ etcdctl watch --prev-kv foo


# 在另外一个终端: etcdctl put foo bar_latest


PUT


foo         # 键


bar_new     # 在修改前键 foo 的上一个值


foo         # 键


bar_latest  # 修改后键 foo 的值

压缩修订版本。

参照上述内容,etcd 保存修订版本以便应用客户端可以读取键的历史版本。但是,为了避免积累无限数量的历史数据,需要对历史的修订版本进行压缩。

下述命令实现了压缩修订版本:

$ etcdctl compact 5


compacted revision 5 #在压缩修订版本之前的任何修订版本都不可访问


$ etcdctl get --rev=4 foo


{"level":"warn","ts":"2020-05-04T16:37:38.020+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-c0d35565-0584-4c07-bfeb-034773278656/127.0.0.1:2379","attempt":0,"error":"rpc error: code = OutOfRange desc = etcdserver: mvcc: required revision has been compacted"}


Error: etcdserver: mvcc: required revision has been compacted

lease(租约)

lease 意为租约,类似于 Redis 中的 TTL(Time To Live)。etcd 中的键值对可以绑定到租约上,实现。在实际应用中,常用来实现服务的心跳,即服务在启动时获取租约,将租约与服务地址绑定,并写入 etcd 服务器,为了保持心跳状态,服务会定时刷新租约。

应用客户端可以为 etcd 集群里面的键授予租约。当键被附加到租约时,它的存活时间被绑定到租约的存活时间,而租约的存活时间相应的被 TTL 管理。在授予租约时,每个租约的最小 TTL 值由应用客户端指定。

# 授予租约,TTL 为 100 秒


$ etcdctl lease grant 100


lease 694d71ddacfda227 granted with TTL(10s)


# 附加键 foo 到租约 694d71ddacfda227


$ etcdctl put --lease=694d71ddacfda227 foo10 bar


OK

在实际的操作中,,避免来不及操作而出现如下错误:

{"level":"warn","ts":"2020-12-04T17:12:27.957+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-f87e9b9e-a583-453b-8781-325f2984cef0/127.0.0.1:2379","attempt":0,"error":"rpc error: code = NotFound desc = etcdserver: requested lease not found"}

应用通过租约 ID 可以撤销租约。撤销租约将删除所有附带的 key。

我们进行下列操作:

$ etcdctl lease revoke 694d71ddacfda227


lease 694d71ddacfda227 revoked


$ etcdctl get foo10

应用程序可以通过刷新其 TTL 保持租约存活,因此不会过期。

$ etcdctl lease keep-alive 694d71ddacfda227


lease 694d71ddacfda227 keepalived with TTL(100)


lease 694d71ddacfda227 keepalived with TTL(100)


...

应用客户端可以查询租赁信息,检查续订或租赁的状态,是否存在或者是否已过期。应用客户端还可以查询特定租约绑定的 key。

我们进行下述操作:

$ etcdctl lease grant 300


lease 694d71ddacfda22c granted with TTL(300s)


$ etcdctl put --lease=694d71ddacfda22c foo10 bar


OK

获取有关租赁信息以及哪些 key 绑定了租赁信息:

$ etcdctl lease timetolive 694d71ddacfda22c


lease 694d71ddacfda22c granted with TTL(300s), remaining(282s)


$ etcdctl lease timetolive --keys 694d71ddacfda22c


lease 694d71ddacfda22c granted with TTL(300s), remaining(220s), attached keys([foo10])

小结

这一讲我们主要介绍了 etcdctl 相关命令的说明以及数据库命令的使用实践。etcdctl 为用户提供一些简洁的命令,用户通过 etcdctl 可以直接与 etcd 服务端交互。etcdctl 客户端提供的操作与 HTTP API 基本上是对应的,甚至可以替代 HTTP API 的方式。通过 etcdctl 客户端工具的学习,对于我们快速熟悉 etcd 组件的功能和入门使用非常有帮助。

本讲内容如下:

学完这一讲内容,想必你对 etcd 的常用功能已经有了一个整体的了解,但是如果在 etcd 集群信息变更的情况下,etcdctl 如何稳定地访问 etcd 服务实例,非 gRPC 客户端又该如何访问 etcd 服务端呢?这也是我们下一讲的主要内容,希望你能提前思考,也欢迎你在留言区和我交流,我们下一讲再见。

上一讲我们介绍了 etcd 的几种安装部署方式以及 TLS 安全加密等知识点。安装好 etcd 后,我们将开始体验如何使用 etcd。这一讲,我将会基于 etcd 自带的客户端工具——etcdctl 来演示 etcd 常用的一些操作,帮助你快速入手 etcd。

etcdctl 客户端

etcdctl 是一个命令行客户端,便于我们进行,我们刚开始熟悉 etcd 功能时可以通过 etdctl 客户端熟悉相关操作。etcdctl 在两个不同的 etcd 版本(v2 和 v3)下的功能和使用方式也完全不同。一般通过如下方式来指定使用 etcd 的版本:

export ETCDCTL_API=2


export ETCDCTL_API=3

我们的专栏课程主要讲解 API 3。etcd 项目二进制发行包中已经包含了 etcdctl 工具,通过 etcd 安装包中的 etcdctl 可执行文件可以进行调用。下面我们先来看看 etcd 的常用命令有哪些,并进行实践应用。

常用命令介绍

我们首先来看下 etcdctl 支持哪些命令,通过etcdctl -h命令查看:

$ etcdctl -h


NAME:


	etcdctl - A simple command line client for etcd3.


USAGE:


	etcdctl [flags]


VERSION:


3.4.4


API VERSION:


3.4

COMMANDS:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vURe4GIj-1657696928598)(https://s2.loli.net/2022/07/13/SLjwZvNzMC6VEHg.png)]

OPTIONS:

etcdctl 支持的命令大体上分为两类。其中数据库的操作命令是最常用的命令,我们将在下面具体介绍。其他的命令如用户、角色、授权、认证相关,你可以根据语法自己尝试一下。

数据库操作

数据库操作基本围绕着对键值和目录的 CRUD 操作(即增删改查),及其对应的生命周期管理。我们上手这些操作其实很方便,因为这些操作是符合 REST 风格的一套 API 操作。

etcd 在键的组织上采用了类似文件系统中目录的概念,即,我们指定的键可以作为键名,如:testkey,实际上,此时键值对放于根目录 / 下面。我们也可以为键的存储,如 /cluster/node/key;如果不存在 /cluster/node 目录,则 etcd Server 将会创建相应的目录结构。

下面我们基于键操作、watch、lease 三类分别介绍 etcdctl 的使用与实践。

键操作

键操作包括最常用的增删改查操作,包括 PUT、GET、DELETE 等命令。

。例如:

$ etcdctl put /test/foo1 "Hello world"


$ etcdctl put /test/foo2 "Hello world2"


$ etcdctl put /test/foo3 "Hello world3"

成功写入三对键值,/test/foo1、/test/foo2 和 /test/foo3。

。例如获取 /testdir/testkey 对应的值:

$ etcdctl get /testdir/testkey


Hello world

除此之外, etcdctl 的 GET 命令还提供了根据指定的键(key),获取其对应的十六进制格式值,即以十六进制格式返回:

$ etcdctl get /test/foo1 --hex


\x2f\x74\x65\x73\x74\x64\x69\x72\x2f\x74\x65\x73\x74\x6b\x65\x79 #键


\x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64 #值

加上--print-value-only可以读取对应的值。十六进制在 etcd 中有多处使用,如 也是十六进制。

GET 范围内的值:

$ etcdctl get /test/foo1 /test/foo3


/test/foo1


Hello world


/test/foo2


Hello world2

可以看到,上述操作获取了大于等于 /test/foo1,且小于 /test/foo3 的键值对。foo3 不在范围之内,因为范围是半开区间 [foo1, foo3),不包含 foo3。

获取某个前缀的所有键值对,通过 --prefix 可以指定前缀:

$ etcdctl get --prefix /test/foo


/test/foo1


Hello world


/test/foo2


Hello world2


/test/foo3


Hello world3

这样就能获取所有以 /test/foo 开头的键值对,当前缀获取的结果过多时,还可以通过 --limit=2 限制获取的数量:

etcdctl get --prefix --limit=2 /test/foo

读取键过往版本的值,应用可能想读取键的被替代的值。

例如,应用可能想。或者,应用可能想,而这些请求可以通过访问键历史记录而来。因为 etcd 集群上键值存储的每个修改都会增加 etcd 集群的全局修订版本,应用可以通过提供旧有的 etcd 修改版本来读取被替代的键。现有如下键值对:

foo = bar         # revision = 2


foo1 = bar2       # revision = 3


foo = bar_new     # revision = 4


foo1 = bar1_new   # revision = 5

以下是访问以前版本 key 的示例:

$ etcdctl get --prefix foo # 访问最新版本的 key


foo


bar_new


foo1


bar1_new


$ etcdctl get --prefix --rev=4 foo # 访问第 4 个版本的 key


foo


bar_new


foo1


bar1


$ etcdctl get --prefix --rev=3 foo #  访问第 3 个版本的 key


foo


bar


foo1


bar1


$ etcdctl get --prefix --rev=2 foo #  访问第 3 个版本的 key


foo


bar


$ etcdctl get --prefix --rev=1 foo #  访问第 1 个版本的 key

应用可能想读取大于等于指定键的 byte 值的键。假设 etcd 集群已经有如下列键:

读取大于等于键 b 的 byte 值的键的命令:

$ etcdctl get --from-key b


b


456


z


789

假设 etcd 集群已经有下列键:

foo = bar


foo1 = bar1


foo3 = bar3


zoo = val


zoo1 = val1


zoo2 = val2


a = 123


b = 456


z = 789

删除键 foo 的命令:

$ etcdctl del foo


1 # 删除了一个键

删除从 foo 到 foo9 范围的键的命令:

$ etcdctl del foo foo9


2 # 删除了两个键

删除键 zoo 并返回被删除的键值对的命令:

$ etcdctl del --prev-kv zoo


1   # 一个键被删除


zoo # 被删除的键


val # 被删除的键的值

删除前缀为 zoo 的键的命令:

$ etcdctl del --prefix zoo


2 # 删除了两个键

删除大于等于键 b 的 byte 值的键的命令:

$ etcdctl del --from-key b


2 # 删除了两个键

watch 键值对的改动

etcd 的 watch 功能是一个常用的功能,我们来看看通过 etcdctl 如何实现 watch 指定的键值对。

watch 监测一个键值的变化,一旦。例如:用户更新 testkey 键值为 Hello watch。

$ etcdctl watch testkey


# 在另外一个终端: etcdctl put testkey Hello watch


testkey


Hello watch

从 foo to foo9 范围内键的命令:

$ etcdctl watch foo foo9


# 在另外一个终端: etcdctl put foo bar


PUT


foo


bar


# 在另外一个终端: etcdctl put foo1 bar1


PUT


foo1


bar1

以 16 进制格式在键 foo 上进行观察的命令:

$ etcdctl watch foo --hex


# 在另外一个终端: etcdctl put foo bar


PUT


\x66\x6f\x6f          # 键


\x62\x61\x72          # 值

观察多个键 foo 和 zoo 的命令:

$ etcdctl watch -i


$ watch foo


$ watch zoo


# 在另外一个终端: etcdctl put foo bar


PUT


foo


bar


# 在另外一个终端: etcdctl put zoo val


PUT


zoo


val

查看 key 的历史改动,应用可能想观察 etcd 中键的历史改动。

例如,应用服务想要获取某个键的所有修改。如果应用客户端一直与 etcd 服务端保持连接,使用 watch 命令就能够实现了。但是当应用或者 etcd 实例出现异常,该键的改动可能发生在出错期间,这样导致了应用客户端没能实时接收这个更新。因此,,为了做到这点,应用客户端可以在观察时指定一个历史修订版本。

首先我们需要完成下述序列的操作:

$ etcdctl put foo bar         # revision = 2


OK


$ etcdctl put foo1 bar1       # revision = 3


OK


$ etcdctl put foo bar_new     # revision = 4


OK


$ etcdctl put foo1 bar1_new   # revision = 5


OK

观察历史改动:

# 从修订版本 2 开始观察键 `foo` 的改动


$ etcdctl watch --rev=2 foo


PUT


foo


bar


PUT


foo


bar_new

从上一次历史修改开始观察:

# 在键 `foo` 上观察变更并返回被修改的值和上个修订版本的值


$ etcdctl watch --prev-kv foo


# 在另外一个终端: etcdctl put foo bar_latest


PUT


foo         # 键


bar_new     # 在修改前键 foo 的上一个值


foo         # 键


bar_latest  # 修改后键 foo 的值

压缩修订版本。

参照上述内容,etcd 保存修订版本以便应用客户端可以读取键的历史版本。但是,为了避免积累无限数量的历史数据,需要对历史的修订版本进行压缩。

下述命令实现了压缩修订版本:

$ etcdctl compact 5


compacted revision 5 #在压缩修订版本之前的任何修订版本都不可访问


$ etcdctl get --rev=4 foo


{"level":"warn","ts":"2020-05-04T16:37:38.020+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-c0d35565-0584-4c07-bfeb-034773278656/127.0.0.1:2379","attempt":0,"error":"rpc error: code = OutOfRange desc = etcdserver: mvcc: required revision has been compacted"}


Error: etcdserver: mvcc: required revision has been compacted

lease(租约)

lease 意为租约,类似于 Redis 中的 TTL(Time To Live)。etcd 中的键值对可以绑定到租约上,实现。在实际应用中,常用来实现服务的心跳,即服务在启动时获取租约,将租约与服务地址绑定,并写入 etcd 服务器,为了保持心跳状态,服务会定时刷新租约。

应用客户端可以为 etcd 集群里面的键授予租约。当键被附加到租约时,它的存活时间被绑定到租约的存活时间,而租约的存活时间相应的被 TTL 管理。在授予租约时,每个租约的最小 TTL 值由应用客户端指定。

# 授予租约,TTL 为 100 秒


$ etcdctl lease grant 100


lease 694d71ddacfda227 granted with TTL(10s)


# 附加键 foo 到租约 694d71ddacfda227


$ etcdctl put --lease=694d71ddacfda227 foo10 bar


OK

在实际的操作中,,避免来不及操作而出现如下错误:

{"level":"warn","ts":"2020-12-04T17:12:27.957+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-f87e9b9e-a583-453b-8781-325f2984cef0/127.0.0.1:2379","attempt":0,"error":"rpc error: code = NotFound desc = etcdserver: requested lease not found"}

应用

标签: ba附带连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台