Etcd 是一个应用一致性哈希算法 (Raft) 在分布式环境下的 key/value 存储服务。利用 Etcd 的个性,应用程序能够在集群中共享信息、配置或作服务发现,Etcd 会在集群的各个节点中复制这些数据并保障这些数据始终正确。
System Requirements >= 8v CPU + 16GB RAM + 50GB SSD
装置应用
动态就是在配置服务之前曾经晓得了节点的地址和集群的大小
源码编译装置
############################
# Build the latest version
############################
# 1. 下载我的项目并编译
$ git clone https://github.com/etcd-io/etcd.git && cd etcd
$ ./build
To build a vendored etcd from the master branch via go get:
# 2. 设置 GOPATH 环境变量
$ export GOPATH='/Users/example/go'
$ go get -v go.etcd.io/etcd
$ go get -v go.etcd.io/etcd/etcdctl
# 3. 启动服务
$ ./bin/etcd
$ $GOPATH/bin/etcd
# 4. 简略应用
$ ./bin/etcdctl put foo bar
OK
部署单机单服务(动态)
##################################
# Running etcd in standalone mode
##################################
# 1. 设置启动的 Node 地址
$ export NODE1='172.16.176.52'
# 2. 创立一个逻辑存储
$ docker volume create --name etcd-data
# 3. 启动 etcd 服务
# 正式的 ectd 端口是 2379 用于客户端连贯,而 2380 用于搭档通信
# --data-dir: 到数据目录的门路
# --initial-advertise-peer-urls: 集群中节点间通信的 URL 地址
# --listen-peer-urls: 集群中节点间通信的 URL 地址
# --advertise-client-urls: 客户端监听的 URL 地址
# --listen-client-urls: 客户端监听的 URL 地址
# --initial-cluster: 启动初始化集群配置
$ docker run -p 2379:2379 -p 2380:2380 --name etcd \
--volume=etcd-data:/etcd-data \
quay.io/coreos/etcd:latest \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name node1 \
--initial-advertise-peer-urls http://${NODE1}:2380 \
--listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://${NODE1}:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--initial-cluster node1=http://${NODE1}:2380
# 4. 列出当初集群中的服务状态
$ etcdctl --endpoints=http://${NODE1}:2379 member list
部署分布式集群服务(动态)
################################
# Running a 3 node etcd cluster
################################
# node1
docker run -p 2379:2379 -p 2380:2380 --name etcd-node-1 \
--volume=/var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:latest \
/usr/local/bin/etcd \
--data-dir=/etcd-data \
--initial-advertise-peer-urls "http://10.20.30.1:2380" \
--listen-peer-urls "http://0.0.0.0:2380" \
--advertise-client-urls "http://10.20.30.1:2379" \
--listen-client-urls "http://0.0.0.0:2379" \
--initial-cluster "etcd-node-1=http://10.20.30.1:2380, etcd-node-2=http://10.20.30.2:2380, etcd-node-3=http://10.20.30.3:2380" \
--initial-cluster-state "new" \
--initial-cluster-token "my-etcd-token"
# node2
docker run -p 2379:2379 -p 2380:2380 --name etcd-node-2 \
--volume=/var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:latest \
/usr/local/bin/etcd \
--data-dir=/etcd-data \
--initial-advertise-peer-urls "http://10.20.30.2:2380" \
--listen-peer-urls "http://0.0.0.0:2380" \
--advertise-client-urls "http://10.20.30.2:2379" \
--listen-client-urls "http://0.0.0.0:2379" \
--initial-cluster "etcd-node-1=http://10.20.30.1:2380, etcd-node-2=http://10.20.30.2:2380, etcd-node-3=http://10.20.30.3:2380" \
--initial-cluster-state "new" \
--initial-cluster-token "my-etcd-token"
# node3
docker run -p 2379:2379 -p 2380:2380 --name etcd-node-3 \
--volume=/var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:latest \
/usr/local/bin/etcd \
--data-dir=/etcd-data \
--initial-advertise-peer-urls "http://10.20.30.3:2380" \
--listen-peer-urls "http://0.0.0.0:2380" \
--advertise-client-urls "http://10.20.30.3:2379" \
--listen-client-urls "http://0.0.0.0:2379" \
--initial-cluster "etcd-node-1=http://10.20.30.1:2380, etcd-node-2=http://10.20.30.2:2380, etcd-node-3=http://10.20.30.3:2380" \
--initial-cluster-state "new" \
--initial-cluster-token "my-etcd-token"
# run etcdctl using API version 3
docker exec etcd /bin/sh -c "export ETCDCTL_API=3 && /usr/local/bin/etcdctl put foo bar"
部署分布式集群服务
# 编辑 docker-compose.yml 文件
version: "3.6"
services:
node1:
image: quay.io/coreos/etcd
volumes:
- node1-data:/etcd-data
expose:
- 2379
- 2380
networks:
cluster_net:
ipv4_address: 172.16.238.100
environment:
- ETCDCTL_API=3
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node1
- --initial-advertise-peer-urls
- http://172.16.238.100:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.100:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
node2:
image: quay.io/coreos/etcd
volumes:
- node2-data:/etcd-data
networks:
cluster_net:
ipv4_address: 172.16.238.101
environment:
- ETCDCTL_API=3
expose:
- 2379
- 2380
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node2
- --initial-advertise-peer-urls
- http://172.16.238.101:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.101:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
node3:
image: quay.io/coreos/etcd
volumes:
- node3-data:/etcd-data
networks:
cluster_net:
ipv4_address: 172.16.238.102
environment:
- ETCDCTL_API=3
expose:
- 2379
- 2380
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node3
- --initial-advertise-peer-urls
- http://172.16.238.102:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.102:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
volumes:
node1-data:
node2-data:
node3-data:
networks:
cluster_net:
driver: bridge
ipam:
driver: default
config:
-
subnet: 172.16.238.0/24
# 应用启动集群
docker-compose up -d
# 之后应用如下命令登录到任一节点测试 etcd 集群
docker exec -it node1 bash
# etcdctl member list
422a74f03b622fef, started, node1, http://172.16.238.100:2380, http://172.16.238.100:2379
ed635d2a2dbef43d, started, node2, http://172.16.238.101:2380, http://172.16.238.101:2379
daf3fd52e3583ffe, started, node3, http://172.16.238.102:2380, http://172.16.238.102:2379
etcd 罕用配置参数
--name #指定节点名称
--data-dir #指定节点的数据存储目录,用于保留日志和快照
--addr #颁布的 IP 地址和端口;默认为 127.0.0.1:2379
--bind-addr #用于客户端连贯的监听地址;默认为–addr 配置
--peers #集群成员逗号分隔的列表;例如 127.0.0.1:2380,127.0.0.1:2381
--peer-addr #集群服务通信的颁布的 IP 地址;默认为 127.0.0.1:2380
-peer-bind-addr #集群服务通信的监听地址;默认为 -peer-addr 配置
--wal-dir #指定节点的 wal 文件的存储目录,若指定了该参数 wal 文件会和其余数据文件离开存储
--listen-client-urls #监听 URL;用于与客户端通信
--listen-peer-urls #监听 URL;用于与其余节点通信
--initial-advertise-peer-urls #告知集群其余节点 URL
--advertise-client-urls #告知客户端 URL
--initial-cluster-token #集群的 ID
--initial-cluster #集群中所有节点
--initial-cluster-state new #示意从无到有搭建 etcd 集群
--discovery-srv #用于 DNS 动静服务发现,指定 DNS SRV 域名
--discovery #用于 etcd 动静发现,指定 etcd 发现服务的 URL
数据存储
etcd 的数据存储有点像 PG 数据库的存储形式
etcd 目前反对 V2 和 V3 两个大版本,这两个版本在实现上有比拟大的不同,一方面是对外提供接口的形式,另一方面就是底层的存储引擎,V2 版本的实例是一个纯内存的实现,所有的数据都没有存储在磁盘上,而 V3 版本的实例就反对了数据的长久化。
咱们都晓得 etcd 为咱们提供了 key/value 的服务目录存储。
# 设置键值对
$ etcdctl set name escape
# 获取形式
$ etcdctl get name
escape
应用 etcd 之后,咱们会疑难数据都存储到的那里呢?数据默认会寄存在 /var/lib/etcd/default/ 目录。咱们会发现数据所在的目录,会被分为两个文件夹中,别离是 snap 和 wal 目录。
- snap
- 寄存快照数据,存储 etcd 的数据状态
- etcd 避免 WAL 文件过多而设置的快照
- wal
- 寄存预写式日志
- 最大的作用是记录了整个数据变动的全副历程
- 在 etcd 中,所有数据的批改在提交前都要先写入到 WAL 中
# 目录构造
$ tree /var/lib/etcd/default/
default
└── member
├── snap
│ ├── 0000000000000006-0000000000046ced.snap
│ ├── 0000000000000006-00000000000493fe.snap
│ ├── 0000000000000006-000000000004bb0f.snap
│ ├── 0000000000000006-000000000004e220.snap
│ └── 0000000000000006-0000000000050931.snap
└── wal
└── 0000000000000000-0000000000000000.wal
应用 WAL 进行数据的存储使得 etcd 领有两个重要性能,那就是故障疾速复原和数据回滚 / 重做。
- 故障疾速复原就是当你的数据受到毁坏时,就能够通过执行所有 WAL 中记录的批改操作,疾速从最原始的数据恢复到数据损坏前的状态。
- 数据回滚重做就是因为所有的批改操作都被记录在 WAL 中,须要回滚或重做,只须要方向或正向执行日志中的操作即可。
既然有了 WAL 实时存储了所有的变更,为什么还须要 snapshot 呢?随着使用量的减少,WAL 存储的数据会暴增。为了避免磁盘很快就爆满,etcd 默认每 10000 条记录做一次 snapshot 操作,通过 snapshot 当前的 WAL 文件就能够删除。而通过 API 能够查问的历史 etcd 操作默认为 1000 条。
首次启动时,etcd 会把启动的配置信息存储到 data-dir 参数指定的数据目录中。配置信息包含本地节点的 ID、集群 ID 和初始时集群信息。用户须要防止 etcd 从一个过期的数据目录中重新启动,因为应用过期的数据目录启动的节点会与集群中的其余节点产生不统一。所以,为了最大化集群的安全性,一旦有任何数据损坏或失落的可能性,你就应该把这个节点从集群中移除,而后退出一个不带数据目录的新节点。
Raft 算法
保障一致性的共识算法
在每一个分布式系统中,etcd 往往都表演了十分重要的位置,因为很多服务配置发现以及配置的信息都存储在 etcd 中,所以整个集群可用性的下限往往就是 etcd 的可用性,而应用 3 ~ 5 个 etcd 节点形成高可用的集群往往都是惯例操作。
正是因为 etcd 在应用的过程中会启动多个节点,如何解决几个节点之间的分布式一致性就是一个比拟有挑战的问题了。解决多个节点数据一致性的计划其实就是共识算法,etcd 应用的就是 Raft 共识算法。
Raft 从一开始就被设计成一个易于了解和实现的共识算法,它在容错和性能上与 Paxos 协定比拟相似,区别在于它将分布式一致性的问题分解成了几个子问题,而后一一进行解决。
每一个 Raft 集群中都蕴含多个服务器,在任意时刻,每一台服务器只可能处于 Leader、Follower 以及 Candidate 三种状态;在处于失常的状态时,集群中只会存在一个 Leader 状态,其余的服务器都是 Follower 状态。
所有的 Follower 节点都是被动的,它们不会被动收回任何的申请,只会响应 Leader 和 Candidate 收回的申请。对于每一个用户的可变操作,都会被路由给 Leader 节点进行解决,除了 Leader 和 Follower 节点之外,Candidate 节点其实只是集群运行过程中的一个长期状态。
Raft 集群中的工夫也被切分成了不同的几个任期(Term),每一个任期都会由 Leader 的选举开始,选举完结后就会进入失常操作的阶段,直到 Leader 节点呈现问题才会开始新一轮的抉择。
每一个服务器都会存储以后集群的最新任期,它就像是一个枯燥递增的逻辑时钟,可能同步各个节点之间的状态,以后节点持有的任期会随着每一个申请被传递到其余的节点上。Raft 协定在每一个任期的开始时都会从一个集群中选出一个节点作为集群的 Leader 节点,这个节点会负责集群中的日志的复制以及管理工作。
咱们将 Raft 协定分成三个子问题:节点选举、日志复制以及安全性。
服务发现
服务发现是 etcd 服务的次要的用处之一
服务发现要解决的也是分布式系统中最常见的问题之一,即在同一个分布式集群中的过程或服务,要如何能力找到对方并建设连贯。实质上来说,服务发现就是想要理解集群中是否有过程在监听 UDP 或 TCP 端口,并且通过名字就能够查找和连贯。要解决服务发现的问题,须要有上面三大支柱,缺一不可。
- 一个强一致性、高可用的服务存储目录
- 基于 Raft 算法的 etcd 天生就是这样一个强一致性高可用的服务存储目录
- 一种注册服务和监控服务衰弱状态的机制
- 用户能够在 etcd 中注册服务,并且对注册的服务设置 key TTL 值,定时放弃服务的心跳以达到监控服务衰弱状态的成果。
- 一种查找和连贯服务的机制
- 为了确保连贯,咱们能够在每个服务机器上都部署一个 Proxy 模式的 etcd,这样就能够确保能拜访 etcd 集群的服务都能相互连贯。
日常开发集群治理性能中,如果要设计能够动静调整集群大小。那么首先就要反对服务发现,就是说当一个新的节点启动时,能够将本人的信息注册给 master,而后让 master 把它退出到集群里,敞开之后也能够把本人从集群中删除。etcd 提供了很好的服务注册与发现的根底功,咱们采纳 etcd 来做服务发现时,能够把精力用于服务自身的业务解决上。
应用办法
etcd 在键的组织上采纳了层次化的空间结构,相似于文件系统中目录的概念,数据库操作围绕对键值和目录的 CRUD 残缺生命周期的治理。etcdctl 是一个命令行的客户端,它提供了一下简洁的命令,可了解为命令工具集,能够不便咱们在对服务进行测试或者手动批改数据库内容。etcdctl 与其余 xxxctl 的命令原理及操作相似,如 systemctl 等等。
- 对象为键值
- 对象为目录
- 非数据库操作命令
# 列出 etcd 集群中的实例
$ etcdctl member list
# 增加 etcd 集群中的实例
$ etcdctl member add < 实例 >
# 删除 etcd 集群中的实例
$ etcdctl member remove < 实例 >
# 更新 etcd 集群中的实例
$ etcdctl member update < 实例 >
- etcdctl 罕用配置参数
--name #指定节点名称
灾备复原
Etcd 集群备份和数据恢复以及优化运维
etcd 被设计为能接受集群主动从长期失败 (例如机器重启) 中复原,而且对于一个有 N 个成员的集群能答应 (N-1)/2 的继续失败。当一个成员继续失败时,不论是因为硬件失败或者磁盘损坏,它失落到集群的拜访。如果集群继续失落超过 (N-1)/2 的成员,则它只能悲惨的失败,无可救药的失去法定人数(quorum)。一旦法定人数失落,集群无奈达到一致性而导致无奈持续接管更新。为了从劫难失败中复原数据,etcd v3 提供快照和修复工具来重建集群而不失落 v3 键数据。
etcd 证书制作
因为 v3 版本的 etcd 证书是基于 IP 的,所以每次新增 etcd 节点都须要从新制作证书。为了咱们更不便的应用,能够查看这个链接来 etcd 证书制作。详情: https://github.com/cloudflare…
快照键空间
复原集群,首先须要来自 etcd 成员的键空间的快照。疾速能够是用 etcdctl snapshot save 命令从流动成员中获取。或者是从 etcd 数据目录复制 member/snap/db 文件。例如,下列命令快照在 $ENDPOINT 上服务的键空间到文件 snapshot.db。
# 集群备份 etcd 数据快照
# $ENDPOINT => http://10.20.30.1:2379
$ ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshot.db
# 在单节点 etcd 上执行上面的命令就能够对 etcd 进行数据备份
# 每两个小时备份一次数据并上传到 S3 上,并保留最近两天的数据
$ ETCDCTL_API=3 etcdctl snapshot save /var/lib/etcd_backup/etcd_$(date "+%Y%m%d%H%M%S").db
复原集群
为了复原集群,应用之前任意节点上备份的快照 “db” 文件。复原的手,能够应用 etcdctl snapshot restore 命令来复原 etcd 数据目录,此时所有成员应该应用雷同的快照复原。因为复原数据死后,会笼罩某些快照元数据 (特地是成员 ID 和集群 ID) 信息,集群内的成员可能会失落它之前的标识。因而为了从快照启动集群,复原必须启动一个新的逻辑集群。
在复原时,快照完整性的测验是可选的。如果快照是通过 etcdctl snapshot save 失去的话,应用 etcdctl snapshot restore 命令复原的时候,会查看 hash 值的完整性。如果快照是从数据目录复制而来,则没有完整性校验,因而它只能通过应用 –skip-hash-check 来复原。
上面为一个 3 成员的集群创立新的 etcd 数据目录:
$ etcdctl snapshot restore snapshot.db \
--name m1 \
--initial-cluster m1=http:/host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host1:2380
$ etcdctl snapshot restore snapshot.db \
--name m2 \
--initial-cluster m1=http:/host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host2:2380
$ etcdctl snapshot restore snapshot.db \
--name m3 \
--initial-cluster m1=http:/host1:2380,m2=http://host2:2380,m3=http://host3:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-advertise-peer-urls http://host3:2380
下一步, 用新的数据目录启动 etcd 服务,当初复原的集群能够应用并提供来自快照的键空间服务。
$ etcd \
--name m1 \
--listen-client-urls http://host1:2379 \
--advertise-client-urls http://host1:2379 \
--listen-peer-urls http://host1:2380 &
$ etcd \
--name m2 \
--listen-client-urls http://host2:2379 \
--advertise-client-urls http://host2:2379 \
--listen-peer-urls http://host2:2380 &
$ etcd \
--name m3 \
--listen-client-urls http://host3:2379 \
--advertise-client-urls http://host3:2379 \
--listen-peer-urls http://host3:2380 &
作者: Escape
https://escapelife.github.io/…