xdays

etcd基础

March 03, 2016

简介

etcd 是一个分布式 kv 存储,与我前面介绍的Consul有些类似,底层都是基于raft协议的,它的主要用途包括为应用提供集中的配置管理和服务发现。

安装

etcd 是 go 语言开发的,所以安装成本非常低,一般我们用 systemd 来管理 etcd,这里我们简单过下安装过程:

curl -L  https://github.com/coreos/etcd/releases/download/v2.2.5/etcd-v2.2.5-linux-amd64.tar.gz -o etcd-v2.2.5-linux-amd64.tar.gz
tar xzvf etcd-v2.2.5-linux-amd64.tar.gz
cd etcd-v2.2.5-linux-amd64
mkdir -p /opt/etcd/bin && cp etcd etcdctl /opt/etcd/bin/

然后准备 systemd 配置文件 /usr/lib/systemd/system/etcd.service

[Unit]
Description=etcd

[Service]
Type=notify
Restart=always
RestartSec=10s
LimitNOFILE=40000
Environment=ETCD_DATA_DIR=/opt/etcd/default.etcd
Environment=ETCD_NAME=%m
Environment=ETCD_ELECTION_TIMEOUT=1200
Environment="ETCD_LISTEN_PEER_URLS=http://{{host.ip}}:2380,http://{{host.ip}}:7001"
Environment="ETCD_ADVERTISE_CLIENT_URLS=http://{{host.ip}}:2379,http://{{host.ip}}:4001"
Environment="ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379"
ExecStart=/opt/everstring/etcd/bin/etcd

[Install]
WantedBy=multi-user.target

注意: 上述配置中 {{host.ip}} 要替换成本机从外面可以访问的 IP。

然后重新加载 systemd 配置

systemctl daemon-reload

启动

单机模式

对于单机模式,没有需要特殊说明,直接启动 etcd 即是以单机模式运行:

systemctl start etcd

然后可以运行客户端命令查看集群状态:

etcdctl cluster-health

集群模式

对于集群模式,我们有几个方面要说下。

  1. 架设集群
  2. 增删成员

架设集群

根据官方集群文档的介绍,有两种架设集群的方式:

  1. static
  2. etcd discovery

官方建议 etcd 集群的数量是奇数个,这样能保证在网络分割的时候不会选出来两个 leader。这里我重点说下 Static 的方式,只要理解了这种方式 etc discovery 就很好理解了。先来看下集群的启动命令:

etcd0

etcd --name etcd0 -advertise-client-urls http://192.168.99.101:2379 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-advertise-peer-urls http://192.168.99.101:2380 \
-initial-cluster-token etcd-cluster-1 \
-initial-cluster etcd0=http://192.168.99.101:2380,etcd1=http://192.168.99.102:2380,etcd2=http://192.168.99.103:2380 \
-initial-cluster-state new

etcd1

etcd --name etcd1 -advertise-client-urls http://192.168.99.102:2379 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-advertise-peer-urls http://192.168.99.102:2380 \
-initial-cluster-token etcd-cluster-1 \
-initial-cluster etcd0=http://192.168.99.101:2380,etcd1=http://192.168.99.102:2380,etcd2=http://192.168.99.103:2380 \
-initial-cluster-state new

etcd2

etcd --name etcd2 -advertise-client-urls http://192.168.99.103:2379 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-advertise-peer-urls http://192.168.99.103:2380 \
-initial-cluster-token etcd-cluster-1 \
-initial-cluster etcd0=http://192.168.99.101:2380,etcd1=http://192.168.99.102:2380,etcd2=http://192.168.99.103:2380 \
-initial-cluster-state new

要让一组 etcd 实例组成集群:首先要给集群一个标识,由--initial-cluster-token指定;然后在启动的时候要让集群里的 etcd 知道彼此,由--initial-cluster指定;此外既然集群的每个成员要接收客户端的连接就要在集群里通告自己提供给客户端连接的 endpoint,由-advertise-client-urls指定。

但是,static 方式架设集群的前提是我们已经知道了集群中所有 etcd 的 ip 列表了,如果我们在启动第一个 etcd 实例的时候还不知道第二个 etcd 实例的 ip 的话就要用 etcd discovery 的方式来动态发现集群中的所有的 etcd 实例列表。具体示例请参考官方集群文档

增删成员

这里要指出:

  1. 在集群可用的时候,也就是说集群中大多数 etcd 实例仍然存活的时候,我们可以通过 etcdctl 来增删成员;
  2. 在集群不可用的时候,也就是说离线成员超过半数,但是离线成员的数据依然存在,可以直接重启 etcd 成员使集群恢复健康状态
  3. 在集群不可用的时候,也就是说离线成员超过半数,而且离线成员数据全部丢失,这种情况只能通过离线恢复来重建整个集群,具体可参考灾难恢复

下面我演示下如何增删成员:

新增成员

在现有的集群里增加要加入的节点信息,

etcdctl -C http://192.168.99.101:2379 member add etcd2 http://192.168.99.103:2380

启动新增的节点

etcd --name etcd2 -advertise-client-urls http://192.168.99.103:2379 \
-listen-client-urls http://0.0.0.0:2379 \
-listen-peer-urls http://0.0.0.0:2380 \
-initial-advertise-peer-urls http://192.168.99.103:2380 \
-initial-cluster-token etcd-cluster-1 \
-initial-cluster etcd0=http://192.168.99.101:2380,etcd1=http://192.168.99.102:2380,etcd2=http://192.168.99.103:2380 \
-initial-cluster-state existing

删除成员

etcdctl -C http://192.168.99.101:2379 member remove 9636be876f777946

注意: 如果一个 etcd 实例从集群中剔除,实例会自动退出,而且不能再加入集群;已删除的 etcd 实例,只有清空数据后重新按照新增成员的步骤才能重新加入集群。

使用

key 的增删改查

etcdctl set /key1 value1
etcdctl set --swap-with-value value1 /key1 value2
etcdctl rm /key1
etcdctl update /key1 /value2
etcdctl get /key1

key 的 watch

etcdctl mkdir /test
etcdctl watch --recursive /test

然后在 test 目录下 set 一个 key 就能看到 watch 的效果

常见问题

  1. etcd 监听在 0.0.0.0,但是 etcdctl 却无法连接到。这种情况可能因为 etcd 没有指定 -advertise-client-urls ,然后 etcd 就会在集群里宣告默认的 127.0.1,这样 etcdctl 从集群里拿到的就是 127.0.0.1 的地址。解决办法是,给 etcdctl 加 --no-sync 参数强制 etcdctl 不从集群里同步状态,然后通过 --peers 直接去连接 etcd。