跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

任务

本文提供了针对使用 etcd 构建应用程序的开发人员以及负责部署、配置和维护 etcd 集群的操作员的任务导向指南。

1 - 运维任务

部署、配置和维护 etcd 集群的操作指南

1.1 - 如何搭建演示集群

etcd 集群部署指南
01_etcd_clustering_2016050601

在每个 etcd 节点上,指定集群成员:

TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

在每台机器上运行以下命令:

# For machine 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For machine 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

# For machine 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

或使用我们的公开发现服务:

curl https://discovery.etcd.io/new?size=3
https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

# grab this token
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
DISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92

THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
	--discovery ${DISCOVERY} \
	--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

现在 etcd 已准备就绪!使用 etcdctl 连接 etcd:

export ETCDCTL_API=3
HOST_1=10.240.0.17
HOST_2=10.240.0.18
HOST_3=10.240.0.19
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379

etcdctl --endpoints=$ENDPOINTS member list

1.2 - 如何在 etcd 集群中进行领导者选举

通过 etcdctl 客户端开展领导者选举的步骤

先决条件

  • 确保已安装 etcd 和 etcdctl 。
  • 检查 etcd 集群是否处于活跃状态。

进行领导者选举

etcdctl 命令用于在 etcd 集群中执行选举操作。该命令确保同一时间仅有一个客户端可成为领导者。

etcdctl --endpoints=$ENDPOINTS elect <election-name> [proposal]

etcdctl --endpoints=$ENDPOINTS elect election-name p1

选项

  • --endpoints : $ENDPOINTS

每个 etcd 集群成员的地址。

  • election-name 字符串

用于选举的字符串标识符。所有竞争领导权的参与者必须使用相同的选举名称。

  • leader-name 字符串

新领导者的提案值。

示例

./etcdctl elect my-election proposal1
my-election/694d99fafea88404
proposal1

another election:
./etcdctl elect new-election proposal1
new-election/694d99fafea8840f
proposal1

1.3 - 如何检查集群状态

etcd 集群状态检查指南

先决条件

检查整体状态

使用 endpoint status 检查 --endpoints 标志中指定的每个端点的总体状态:

etcdctl endpoint status (--endpoints=$ENDPOINTS|--cluster)

选项

--cluster[=false]: use all endpoints from the cluster member list

检查健康状况

使用 endpoint health 检查 --endpoints 标志中指定的每个端点的健康状态:

etcdctl endpoint health (--endpoints=$ENDPOINTS|--cluster)

选项

--cluster[=false]: use all endpoints from the cluster member list

检查键值哈希

使用 endpoint hashkv 检查 --endpoints 标志中指定的每个端点的 KV 历史哈希值:

etcdctl endpoint hashkv (--endpoints=$ENDPOINTS|--cluster) [rev=$REV]

选项

--cluster[=false]: use all endpoints from the cluster member list
--rev=0: maximum revision to hash (default: latest revision)

继承自父命令的选项

--endpoints="127.0.0.1:2379": gRPC endpoints
-w, --write-out="simple": set the output format (fields, json, protobuf, simple, table)

示例

etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status

+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|    ENDPOINT      |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 10.240.0.17:2379 | 4917a7ab173fabe7 |  3.5.0  |   45 kB |      true |      false |         4 |      16726 |              16726 |        |
| 10.240.0.18:2379 | 59796ba9cd1bcd72 |  3.5.0  |   45 kB |     false |      false |         4 |      16726 |              16726 |        |
| 10.240.0.19:2379 | 94df724b66343e6c |  3.5.0  |   45 kB |     false |      false |         4 |      16726 |              16726 |        |
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------|
etcdctl --endpoints=$ENDPOINTS endpoint health

10.240.0.17:2379 is healthy: successfully committed proposal: took = 3.345431ms
10.240.0.19:2379 is healthy: successfully committed proposal: took = 3.767967ms
10.240.0.18:2379 is healthy: successfully committed proposal: took = 4.025451ms
etcdctl --cluster endpoint hashkv  --write-out=table

+------------------+------------+---------------+
|     ENDPOINT     |    HASH    | HASH REVISION |
+------------------+------------+---------------+
| 10.240.0.17:2379 | 3892279174 |             3 |
| 10.240.0.18:2379 | 3892279174 |             3 |
| 10.240.0.19:2379 | 3892279174 |             3 |
+------------------+------------+---------------+

1.4 - 如何保存数据库

etcd 数据库快照的使用指南

先决条件

快照数据库

snapshot 用于保存 etcd 数据库的指定时间点快照:

etcdctl --endpoints=$ENDPOINT snapshot save DB_NAME

全局选项

etcdctl

--endpoints=[127.0.0.1:2379], gRPC endpoints

快照只能从一个 etcd 节点请求,因此 --endpoints 标志中应仅包含一个端点。

etcd 工具

-w, --write-out string   set the output format (fields, json, protobuf, simple, table) (default "simple")

示例

11_etcdctl_snapshot_2016051001
ENDPOINTS=$HOST_1:2379
etcdctl --endpoints=$ENDPOINTS snapshot save my.db

Snapshot saved at my.db
etcdutl --write-out=table snapshot status my.db

+---------+----------+------------+------------+
|  HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+---------+----------+------------+------------+
| c55e8b8 |        9 |         13 | 25 kB      |
+---------+----------+------------+------------+

1.5 - 如何添加和删除成员

etcd 集群成员管理指南

member 用于添加、删除或更新成员关系:

13_etcdctl_member_2016062301
# For each machine
TOKEN=my-etcd-token-1
CLUSTER_STATE=new
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_3=etcd-node-3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

然后使用 member remove 和 member add 命令替换成员:

# get member ID
export ETCDCTL_API=3
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_3=10.240.0.15
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 member list

# remove the member
MEMBER_ID=278c654c9a6dfd3b
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \
	member remove ${MEMBER_ID}

# add a new member (node 4)
export ETCDCTL_API=3
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \
	member add ${NAME_4} \
	--peer-urls=http://${HOST_4}:2380

接下来,使用 --initial-cluster-state existing 标志启动新成员:

# [WARNING] If the new member starts from the same disk space,
# make sure to remove the data directory of the old member
#
# restart with 'existing' flag
TOKEN=my-etcd-token-1
CLUSTER_STATE=existing
NAME_1=etcd-node-1
NAME_2=etcd-node-2
NAME_4=etcd-node-4
HOST_1=10.240.0.13
HOST_2=10.240.0.14
HOST_4=10.240.0.16 # new member
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_4}=http://${HOST_4}:2380

THIS_NAME=${NAME_4}
THIS_IP=${HOST_4}
etcd --data-dir=data.etcd --name ${THIS_NAME} \
	--initial-advertise-peer-urls http://${THIS_IP}:2380 \
	--listen-peer-urls http://${THIS_IP}:2380 \
	--advertise-client-urls http://${THIS_IP}:2379 \
	--listen-client-urls http://${THIS_IP}:2379 \
	--initial-cluster ${CLUSTER} \
	--initial-cluster-state ${CLUSTER_STATE} \
	--initial-cluster-token ${TOKEN}

2 - 开发任务

使用 etcd 作为键值存储的应用开发步骤指南

2.1 - 从 etcd 中读取

在集群中读取值

先决条件

  • 安装 etcdctl

步骤

使用 get 子命令从 etcd 读取:

$ etcdctl --endpoints=$ENDPOINTS get foo
foo
Hello World!
$

其中:

  • foo 为请求的键
  • Hello World! 为获取的值

或者,以格式化输出形式:

$ etcdctl --endpoints=$ENDPOINTS --write-out="json" get foo
{"header":{"cluster_id":289318470931837780,"member_id":14947050114012957595,"revision":3,"raft_term":4,
"kvs":[{"key":"Zm9v","create_revision":2,"mod_revision":3,"version":2,"value":"SGVsbG8gV29ybGQh"}]}}
$

其中 write-out="json" 会导致值以 JSON 格式输出(注意:键不会被返回)。

2.2 - 向 etcd 写入

向 etcd 集群添加一个键值对

先决条件

  • 安装 etcdctl

步骤

使用 put 子命令写入键值对:

etcdctl --endpoints=$ENDPOINTS put foo "Hello World!"

其中:

  • foo 为键名称
  • "Hello World!" 为用引号括起的值

2.3 - 如何根据前缀获取键

按前缀获取 etcd 键的指南

先决条件

按前缀获取键

$ etcdctl --endpoints=$ENDPOINTS get PREFIX --prefix

全局选项

--endpoints=[127.0.0.1:2379], gRPC endpoints

选项

--prefix, get a range of keys with matching prefix

示例

03_etcdctl_get_by_prefix_2016050501
etcdctl --endpoints=$ENDPOINTS put web1 value1
etcdctl --endpoints=$ENDPOINTS put web2 value2
etcdctl --endpoints=$ENDPOINTS put web3 value3

etcdctl --endpoints=$ENDPOINTS get web --prefix

2.4 - 如何删除键

删除 etcd 键的指南

先决条件

添加或删除键

del 用于删除指定的键或键范围:

etcdctl del $KEY [$END_KEY]

选项

--prefix[=false]: delete keys with matching prefix
--prev-kv[=false]: return deleted key-value pairs
--from-key[=false]: delete keys that are greater than or equal to the given key using byte compare
--range[=false]: delete range of keys without delay

继承自父命令的选项

--endpoints="127.0.0.1:2379": gRPC endpoints

示例

04_etcdctl_delete_2016050601
etcdctl --endpoints=$ENDPOINTS put key myvalue
etcdctl --endpoints=$ENDPOINTS del key

etcdctl --endpoints=$ENDPOINTS put k1 value1
etcdctl --endpoints=$ENDPOINTS put k2 value2
etcdctl --endpoints=$ENDPOINTS del k --prefix

2.5 - 如何在事务中进行多次写操作

事务性写操作指南

先决条件

术语

以下是本文中使用的部分关键术语的定义,这些术语将在 Example 示例中出现。

术语定义
etcdctl用于与 etcd 服务器交互的命令行工具。
txn 命令txn 命令是“事务”的缩写。它从标准输入读取多个 etcd 请求,并将其作为单个原子事务执行。事务包含一组条件、一组在所有条件均为真时执行的请求,以及一组在任一条件为假时执行的请求。有关更多信息,请参阅 etcdctl 键值命令 。
compare事务(txn)中的 compare 子句用作条件检查,用于判断事务操作是否应继续执行。它确保仅当键值存储的当前状态符合预期条件时才应用变更,从而维护数据一致性,并在并发环境中防止冲突。要了解该命令的结构,请参阅下方 执行事务 章节。

事务

txn 以事务方式处理所有请求:

etcdctl txn --help

事务允许在 etcd 中原子性地执行多个操作,确保所有操作均被应用或全部不被应用。这在执行相关更新时对于维护数据一致性至关重要。有关事务的更多信息,请参见 API 文档 。

示例

考虑一种场景:需要在单个事务中更新用户的电子邮件和电话号码。这可确保两项更新同时生效。

05_etcdctl_transaction_2024101213

0. 使用的变量和标志

变量
/users/{<user_id>/email : 表示用户电子邮件地址的 etcd 键。
/users/<user_id>/phone : 表示用户电话号码的 etcd 键。
标志
--interactive : 用于允许手动输入事务数据的标志。

1. 初始化数据设置

首先,创建一个带有初始数据的用户。

etcdctl put /users/12345/email "old.address@johndoe.com"
etcdctl put /users/12345/phone "123-456-7890"

2. 执行事务

在单个事务中更新用户的电子邮件和电话号码。

etcdctl txn --interactive

compares:
value("/users/12345/email") = "old.address@johndoe.com"

success requests (get, put, delete):
put /users/12345/email "new.address@johndoe.com"
put /users/12345/phone "098-765-4321"

failure requests (get, put, delete):
get /users/12345/email
  • Compare:检查当前邮箱是否为 “old.address@johndoe.com "。这确保事务仅在数据符合预期时才继续执行。
  • Success:如果比较结果为真,更新邮箱和电话号码。
  • Failure:如果比较失败,获取当前邮箱以了解事务未执行的原因。

重要考虑事项

  • 原子性:事务确保电子邮件和电话号码同时更新。如果初始条件(比较)不满足,则不会应用任何更新。
  • 一致性:使用事务可维持数据一致性,尤其是在处理多个相关更新时。
  • 避免在单个事务中对同一键多次写入:在单个事务中不要对同一键写入多个值,这可能导致意外结果。每个键在事务中应仅更新一次。

2.6 - 如何监听键值变化

etcd 键监听指南

先决条件

监听键

watch 以接收后续变更的通知:

etcdctl watch $KEY [$END_KEY]

选项

-i, --interactive[=false]: interactive mode
--prefix[=false]: watch on a prefix if prefix is set
--rev=0: Revision to start watching
--prev-kv[=false]: get the previous key-value pair before the event happens
--progress-notify[=false]: get periodic watch progress notification from server

继承自父命令的选项

--endpoints="127.0.0.1:2379": gRPC endpoints

示例

06_etcdctl_watch_2016050501
etcdctl --endpoints=$ENDPOINTS watch stock1
etcdctl --endpoints=$ENDPOINTS put stock1 1000

etcdctl --endpoints=$ENDPOINTS watch stock --prefix
etcdctl --endpoints=$ENDPOINTS put stock1 10
etcdctl --endpoints=$ENDPOINTS put stock2 20

2.7 - 如何创建租约

etcd 租约创建指南

lease 以 TTL 写入:

07_etcdctl_lease_2016050501
etcdctl --endpoints=$ENDPOINTS lease grant 300
# lease 2be7547fbc6a5afa granted with TTL(300s)

etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS get sample

etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afa
etcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa
# or after 300 seconds
etcdctl --endpoints=$ENDPOINTS get sample

2.8 - 如何创建锁

etcd 分布式锁创建指南

LOCK 使用指定名称获取一个分布式互斥锁。锁获取成功后,将一直持有,直至 etcdctl 终止。

先决条件

创建锁

lock 用于分布式锁:

08_etcdctl_lock_2016050501
etcdctl --endpoints=$ENDPOINTS lock mutex1

选项

  • endpoints - 定义集群中机器地址的逗号分隔列表。
  • ttl - 锁会话的超时时间,单位为秒。