前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >入门篇:从 etcd 名字的由来,到安装部署和使用姿势

入门篇:从 etcd 名字的由来,到安装部署和使用姿势

作者头像
程序员荒生
发布2022-07-14 08:36:45
6170
发布2022-07-14 08:36:45
举报

大家好,我是三十一[0],本次分享分布式神器etcd[1]的 5 种部署方式和 10 种使用姿势,阅读全文预计花费 15 分钟。

在学习 etcd 之前,我们先来聊一聊 etcd 名字的由来[2]。etcd 中的 etc 取自 unix 系统的/etc目录,再加上一个d代表distributed system就组成了 etcd。在 unix 系统中 /etc 目录用于存储系统的配置数据,单从名字看 etcd 可用于存储分布式系统的配置数据,有时候也把 etcd 简单理解为分布式 /etc 配置目录。

etcd 简介

etcd 是一个可靠的分布式 key-value 存储系统,主要用于配置共享服务注册和发现,具有以下特性:

  • 简单:基于 gRPC 定义了清晰、面向用户的 API。
  • 安全:支持可选的客户端 TLS 证书自动认证特性。
  • 快速:支持每秒 10000 次的写入。
  • 可靠:基于 Raft 算法协议保证一致性。

etcd 使用 Go 语言开发,底层基于 Raft 共识算法管理高可用的复制日志。当前已经被许多公司用于关键生产项目,比如:Kubernetes、locksmith、vulcand、Doorman 等。

当然,也有其他组件可以提供配置共享和服务注册和发现的功能,比如最为广泛和大家最为熟知的 Zookeeper,也被很多 Java 系的知名开源项目认可和使用,比如:Hadoop、HBase、Kafka 等。

但 etcd 是唯一一个可以媲美甚至超越 Zookeeper 的组件。

相较之下,Zookeeper 有如下缺点[3]:

  • 复杂:Zookeeper 基于 ZAB 协议,属于类 Paxos 协议,而 Paxos 算法素以复杂难懂闻名;Zookeeper 的使用也比较复杂,需要安装客户端,而官方目前只提供了 Java 和 C 两种语言接口。
  • 发展慢:由于基金会庞大的结构以及松散的管理,导致项目发展缓慢。

而 etcd 作为后起之秀,其优点也很明显:

  • 简单:使用 Go 语言编写部署简单;使用 gRPC 定义接口,支持跨语言、跨平台特性;使用了易于用户理解的 Raft 算法保证一致性,优于 Paxos 算法。
  • 发展快:etcd 正处于高速迭代开发中。
  • 性能优越:官方提供的基准测试数据中,etcd 集群可以支持每秒 10000+ 次的写入,性能优于 Zookeeper。
  • 安全性:etcd 支持 TLS 访问,而 ZooKeeper 在权限控制方面做得略显粗糙。

环境搭建

一、本地安装包部署

「下载」:下载最新的安装包(当前最新:v3.5.4),下载地址:https://github.com/etcd-io/etcd/releases/

「安装」:在解压后的文件目录下etcdetcdctl分别为安装包和客户端的编译后的执行文件,可使用三种方法进行运行配置。

  • 方法一:解压目录下直接运行
  • 方法二:把etcdetcdctl文件复制到GOBIN目录下。
  • 方法三:在环境变量里添加etcdetcdctl文件所在的目录。

注:运行过程中,可能会涉及权限问题,授权即可。

「验证」

代码语言:javascript
复制
# 验证 etcd 版本
$ etcd --version

etcd Version: 3.5.4
Git SHA: 08407ff76
Go Version: go1.16.15
Go OS/Arch: darwin/amd64

# 验证 etcdctl 版本
$ etcdctl version

etcdctl version: 3.5.4
API version: 3.5

二、本地编译部署

「下载」:使用以下命令克隆代码

代码语言:javascript
复制
# 下载最新版
$ git clone https://github.com/etcd-io/etcd.git
# 指定版本下载
$ git clone -b v3.5.4 https://github.com/etcd-io/etcd.git

「编译安装」

代码语言:javascript
复制
# 编译
$ cd etcd
$ make build

# 安装
$ export PATH="$PATH:`pwd`/bin"

「验证」

代码语言:javascript
复制
# 验证 etcd 版本
$ etcd --version

# 验证 etcdctl 版本
$ etcdctl version

# 验证 etcdutl 版本
$ etcdutl version

三、本地集群部署

首先需要安装goreman组件,它基于 Procfile 配置文件管理 etcd 应用进程。

代码语言:javascript
复制
$ go install github.com/mattn/goreman@latest

「启动集群」:源码目录下Procfile脚本已经构建好了本地演示集群,直接运行启动即可

代码语言:javascript
复制
$ goreman start

「验证」

代码语言:javascript
复制
$ etcdctl member list

8211f1d0f64f3269, started, infra1, http://127.0.0.1:12380, http://127.0.0.1:2379, false
91bc3c398fb3c146, started, infra2, http://127.0.0.1:22380, http://127.0.0.1:22379, false
fd422379fda50e48, started, infra3, http://127.0.0.1:32380, http://127.0.0.1:32379, false

该脚本创建包含 3 个 etcd 成员节点的集群,每个集群成员都接收键值的读取和写入。也可以按照Procfile.learner脚本指导,学习集群新增节点的操作。

四、Docker 单机部署

此处通过docker-compose进行实验配置。

「镜像拉取」

代码语言:javascript
复制
$ docker pull bitnami/etcd:3.5.2

「编辑docker-compose.yml」

代码语言:javascript
复制
version: '3.5'

services:
  etcd:
    container_name: builder-etcd
    image: bitnami/etcd:3.5.2
    ports:
      - 2379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data:/bitnami/etcd

networks:
  default:
    name: builder_dev

「启动服务」

代码语言:javascript
复制
$ docker-compose -f docker-compose.yml up

「验证」:验证集群节点的版本

代码语言:javascript
复制
$ docker exec -it builder-etcd /bin/bash -c "etcd --version"

etcd Version: 3.5.2
Git SHA: 99018a77b
Go Version: go1.16.3
Go OS/Arch: linux/amd64

五、Docker 集群部署

「编辑docker-compose.yml」

代码语言:javascript
复制
version: '3.5'

services:
  etcd1:
    container_name: builder-etcd1
    image: bitnami/etcd:3.5.2
    ports:
      - 12379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd1
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data1:/bitnami/etcd

  etcd2:
    container_name: builder-etcd2
    image: bitnami/etcd:3.5.2
    ports:
      - 22379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd2
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data2:/bitnami/etcd

  etcd3:
    container_name: builder-etcd3
    image: bitnami/etcd:3.5.2
    ports:
      - 32379:2379
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1002
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_NAME=etcd3
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - ${DOCKER_ROOT_DIR:-.}/volumes/etcd/data3:/bitnami/etcd

networks:
  default:
    name: builder_dev

部署配置文件 docker-compose.yml 细节,详见etcd docker-compose yml[4]

「启动服务」

代码语言:javascript
复制
$ docker-compose -f docker-compose.yml up

「验证」:验证集群节点的版本

代码语言:javascript
复制
$ docker exec -it builder-etcd1 /bin/bash -c "etcd --version"
$ docker exec -it builder-etcd2 /bin/bash -c "etcd --version"
$ docker exec -it builder-etcd3 /bin/bash -c "etcd --version"

# 输出
etcd Version: 3.5.2
Git SHA: 99018a77b
Go Version: go1.16.3
Go OS/Arch: linux/amd64

API 学习

此处,通过使用etcdctl[5]进行 API 学习验证,etcdctl 是一个用于与 etcd 服务器交互的命令行工具。

「1.查看版本」

代码语言:javascript
复制
$ etcdctl version

etcdctl version: 3.6.0-alpha.0
API version: 3.6

「2.写入 key」

代码语言:javascript
复制
$ etcdctl put foo bar
OK

「3.读取 key」

代码语言:javascript
复制
$ etcdctl get foo
foo
bar
# 只是获取值
$ etcdctl get foo --print-value-only
bar

「4.批量取值」

代码语言:javascript
复制
$ etcdctl put foo1 bar1
$ etcdctl put foo3 bar2
$ etcdctl put foo3 bar3

# 获取从 foo 到 foo3 的值,不包括 foo3
$ etcdctl get foo foo3 --print-value-only 
bar
bar1
bar2

# 获取前缀为 foo 的值
$ etcdctl get --prefix foo --print-value-only
bar
bar1
bar2
bar3

# 获取符合前缀的前两个值
$ etcdctl get --prefix --limit=2 foo --print-value-only
bar
bar1

「5.删除 key」

代码语言:javascript
复制
# 删除 foo 的值
$ etcdctl del foo
1

# 删除 foo 到 foo2 且不包括 foo2 的值
$ etcdctl del foo foo2
1
# 删除前缀为 foo 的所有值
$ etcdctl del --prefix foo
2

「6.监听」

代码语言:javascript
复制
# 监听 foo 单个 key
$ etcdctl watch foo
# 另一个控制台执行:etcdctl put foo bar
PUT
foo
bar

# 同时监视多个值
$ etcdctl watch -i
$ watch foo
$ watch zoo
# 另一个控制台执行: etcdctl put foo bar
PUT
foo
bar

# 另一个控制台执行: etcdctl put zoo val
PUT
zoo
val

# 监视 foo 前缀命中的 key
$ etcdctl watch --prefix foo
# 另一个控制台执行:etcdctl put foo1 bar1
PUT
foo1
bar1
# 另一个控制台执行:etcdctl put fooz1 barz1
PUT
fooz1
barz1

「7.设置租约」当一个 key 被绑定到一个租约上时,它的生命周期与租约的生命周期即绑定。

代码语言:javascript
复制
# 设置10秒后过期时间
$ etcdctl lease grant 10
lease 32698142c52a170a granted with TTL(10s)

# 把 foo 和租约绑定,设置成 10 秒后过期
$ etcdctl put --lease=32698142c52a170a foo bar
OK
$ etcdctl get foo
foo
bar

# 10 秒后,获取不到 foo
$ etcdctl get foo
# 返回空

「8.撤销租约」通过租约 ID 撤销租约,撤销租约将删除其所有绑定的 key。

代码语言:javascript
复制
$ etcdctl lease grant 10
lease 32698142c52a170c granted with TTL(10s)
$ etcdctl put --lease=32698142c52a170c foo bar
OK

# 撤销租约
$ etcdctl lease revoke 32698142c52a170c
lease 32698142c52a170c revoked

$ etcdctl get foo
# 返回空

「9.续约」通过刷新 TTL 值来保持租约的有效,使其不会过期。

代码语言:javascript
复制
# 设置 10 秒后过期租约
$ etcdctl lease grant 10
lease 32698142c52a170f granted with TTL(10s)

# 把 foo 和租约绑定,设置成 10 秒后过期
$ etcdctl put foo bar --lease=32698142c52a170f

# 自动定时执行续约,续约成功后每次租约为 10 秒
$ etcdctl lease keep-alive 32698142c52a170f
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
...

「10.查看租约」查看租约信息,以便续租或查看租约是否仍然存在或已过期

代码语言:javascript
复制
# 设置 50 秒 TTL
$ etcdctl lease grant 50
lease 32698142c52a1711 granted with TTL(50s)

# zoo1 绑定 32698142c52a1711 租约
$ etcdctl put --lease=32698142c52a1711 zoo1 val1
OK

# 查看租约,remaining(32s) 剩余有效时间32秒;--keys 获取租约绑定的 key
$ etcdctl lease timetolive --keys 32698142c52a1711
lease 32698142c52a1711 granted with TTL(50s), remaining(32s), attached keys([zoo1])

注:一个租约支持绑定多个 key

代码语言:javascript
复制
$ etcdctl lease grant 50
lease 32698142c52a1713 granted with TTL(50s)

$ etcdctl put --lease=32698142c52a1713 zoo1 val1
OK

$ etcdctl put --lease=32698142c52a1713 zoo2 val2
OK

$ etcdctl put --lease=32698142c52a1713 zoo3 val3
OK

租约过期后,所有 key 值都会被删除,因此:

  • 当租约只绑定了一个 key 时,想删除这个 key,最好的办法是撤销它的租约,而不是直接删除这个 key。
  • 当租约没有绑定key时,应主动把它撤销掉,单纯删除 key 后,续约操作持续进行,会造成内存泄露。
代码语言:javascript
复制
# 方法一:直接删除`key`
# 设置租约并绑定 zoo1
$ etcdctl lease grant 50
lease 32698142c52a1715 granted with TTL(50s)
$ etcdctl --lease=32698142c52a1715 put zoo1 val1
OK

# 续约
$ etcdctl lease keep-alive 32698142c52a1715
lease 32698142c52a1715 keepalived with TTL(50)

# 另一个控制台执行:etcdctl del zoo1
# 单纯删除 key 后,续约操作持续进行,会造成内存泄露
lease 32698142c52a1715 keepalived with TTL(50)
lease 32698142c52a1715 keepalived with TTL(50)
lease 32698142c52a1715 keepalived with TTL(50)
...

# 方法二:撤销`key`的租约
# 设置租约并绑定 zoo1
$ etcdctl lease grant 50
lease 32698142c52a1717 granted with TTL(50s)
$ etcdctl --lease=32698142c52a1717 put zoo1 val1
OK

# 续约
$ etcdctl lease keep-alive 32698142c52a1717
lease 32698142c52a1717 keepalived with TTL(50)
lease 32698142c52a1717 keepalived with TTL(50)

# 另一个控制台执行:etcdctl lease revoke 32698142c52a1717

# 续约撤销并退出
lease 32698142c52a1717 expired or revoked.
$ etcdctl get zoo1
# 返回空

以上,就是今天的全部内容,几乎包含了 etcd 安装和使用的各种姿势,欢迎各位号友敬请尝试。

References

  • [0] 三十一: http://www.lee31.cn/assets/image/ThirtyOneLee.jpeg
  • [1] etcd: https://github.com/etcd-io/etcd
  • [2] etcd 名字的由来: https://etcd.io/docs/v3.5/faq/
  • [3] https://www.infoq.cn/article/etcd-interpretation-application-scenario-implement-principle/
  • [4] etcd docker-compose yml: https://github.com/liyaodev/docker-compose
  • [5] etcdctl: https://etcd.io/docs/v3.5/dev-guide/interacting_v3/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 李三十一 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • etcd 简介
  • 环境搭建
    • 一、本地安装包部署
      • 二、本地编译部署
        • 三、本地集群部署
          • 四、Docker 单机部署
            • 五、Docker 集群部署
            • API 学习
            • References
            相关产品与服务
            容器镜像服务
            容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档