etcd 是Go语言实现 高可用分布式键值key-value数据库
采用raft协议 一致性算法 CoreOS团队于发起开源项目
etcd作为受到ZooKeeper与doozer启发而催生的项目
分布式系统中的数据分为控制数据和应用数据
etcd的使用场景默认处理的数据都是控制数据
对于应用数据 只推荐数据量很小 但是更新访问频繁的情况
应用场景有如下几类
场景一 服务发现 Service Discovery
场景二 消息发布与订阅
场景三 负载均衡
场景四 分布式通知与协调
场景五 分布式锁 分布式队列
场景六 集群监控与Leader竞选
例需要分布式存储仓库来存储配置信息 且希望这个仓库读写速度快
支持高可用 部署简单 支持http接口 那么就可以使用etcd
前 cloudfoundry 用etcd作为hm9000的应用状态信息存储
kubernetes用etcd来存储docker集群的配置信息等

ETCD的使用场景
配置管理
服务注册于发现
选主
应用调度
分布式队列
分布式锁
选主
Raft协议是用于维护一组服务节点数据一致性的协议
这一组服务节点构成一个集群 并且有一个主节点来对外提供服务
当集群初始化 或者主节点挂掉后 面临一个选主问题
集群中每个节点 任意时刻处于Leader  Follower Candidate这三个角色之一
选举特点如下
当集群初始化时候 每个节点都是Follower角色
集群中存在至多1个有效的主节点 通过心跳与其他节点同步数据
当Follower在一定时间内没有收到来自主节点的心跳 会将自己角色改变为Candidate 并发起一次选主投票
当收到包括自己在内超过半数节点赞成后 选举成功
当收到票数不足半数选举失败 或者选举超时
若本轮未选出主节点 将进行下一轮选举(出现这种情况 是由于多个节点同时选举 所有节点均为获得过半选票)
Candidate节点收到来自主节点的信息后 会立即终止选举过程 进入Follower角色。为了避免陷入选主失败循环
每个节点未收到心跳发起选举的时间是一定范围内的随机值 这样能够避免2个节点同时发起选主

简单 安装配置简单 提供HTTP API 交互
安全 支持SSL证书验证
快速 官方benchmark数据 单实例 每秒2k+读操作
可靠 raft算法 分布式系统数据 可用性和一致性
etcd 项目 //github.com/coreos/etcd/

不建议root安装业务中间件服务 要先进行环境初始化
主机IP     etcd name
192.168.2.213     etcd1
192.168.2.214     etcd2
192.168.2.215     etcd3
新增系统用户etcd
groupadd --system etcd
useradd -s /sbin/nologin -m /var/lib/etcd --system -g etcd etcd
新增配置文件路径
mkdir /etc/etcd
chown -R etcd:etcd /etc/etcd

修改 SELinux 为 disabled
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
下载二进制安装包
curl -s https://api.github.com/repos/etcd-io/etcd/releases/latest | grep browser_download_url | grep linux-amd64 |cut -d '"' -f 4 | wget -qi -
如下进入安装
tar -zxvf etcd-v3.2.32-linux-amd64.tar.gz
cd etcd-v3.2.32-linux-amd64
cp etcd etcdctl /usr/local/bin
chown -R etcd:etcd /usr/local/bin/etcd*
或者 yum install -y etcd
验证安装
$ etcd --version
etcd Version: 3.2.32
Git SHA: 7dc07f2a9
Go Version: go1.12.17
Go OS/Arch: linux/amd64

 $ etcdctl --version
etcdctl version: 3.2.32
API version: 2
配置和启动

1 三台主机分别配置/etc/hosts如下
# etcd
192.168.2.213 etc1
192.168.2.214 etc2
192.168.2.215 etc3

2 三台主机配置新增配置文件/etc/etcd/etcd.conf
注意 etcd1 配置中 ETCD_INITIAL_CLUSTER_STATE 为 new 其余两个为exist
参数ETCD_LISTEN_CLIENT_URLS ETCD_ADVERTISE_CLIENT_URLS ETCD_LISTEN_PEER_URLS  ETCD_INITIAL_ADVERTISE_PEER_URLS 分别为当前主机的IP ETCD_NAME 根据开始的定义配置
# member
ETCD_NAME=etcd1
ETCD_DATA_DIR=/var/lib/etcd
ETCD_LISTEN_CLIENT_URLS=http://192.168.2.213:2379,http://127.0.0.1:2379
ETCD_ADVERTISE_CLIENT_URLS=http://192.168.2.213:2379

# cluster
ETCD_LISTEN_PEER_URLS=http://192.168.2.213:2380
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://192.168.2.213:2380
ETCD_INITIAL_CLUSTER=etcd1=http://192.168.2.213:2380,etcd2=http://192.168.2.214:2380,etcd3=http://192.168.2.215:2380
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN=k8s_etcd

3 三台主机配置systemctl启动方式
/usr/lib/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target
[Service]
User=etcd
Type=notify
WorkingDirectory=/var/lib/etcd/
EnvironmentFile=/etc/etcd/etcd.conf
ExecStart=/usr/local/bin/etcd
Restart=on-failure
RestartSec=10s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target

启动服务
systemctl enable etcd.service
systemctl start etcd.service
systemctl status etcd.service
测试和验收
1 检查各节点
$ etcdctl member list
59b0ee3829e2b866: name=etcd2 peerURLs=http://192.168.2.214:2380 clientURLs=http://192.168.2.214:2379 isLeader=false
a8b07bac1693e30e: name=etcd1 peerURLs=http://192.168.2.213:2380 clientURLs=http://192.168.2.213:2379 isLeader=false
cf682ab5655702b8: name=etcd3 peerURLs=http://192.168.2.215:2380 clientURLs=http://192.168.2.215:2379 isLeader=true

2 检查集群状态
$ etcdctl cluster-health
member 59b0ee3829e2b866 is healthy: got healthy result from http://192.168.2.214:2379
member a8b07bac1693e30e is healthy: got healthy result from http://192.168.2.213:2379
member cf682ab5655702b8 is healthy: got healthy result from http://192.168.2.215:2379
cluster is healthy
3 进行测试
$ etcdctl set /demo 'hello etcd'
hello etcd
$ etcdctl get /demo
hello etcd
故障演练

停掉Leader节点
$ etcdctl member list
59b0ee3829e2b866: name=etcd2 peerURLs=http://192.168.2.214:2380 clientURLs=http://192.168.2.214:2379 isLeader=false
a8b07bac1693e30e: name=etcd1 peerURLs=http://192.168.2.213:2380 clientURLs=http://192.168.2.213:2379 isLeader=true
cf682ab5655702b8: name=etcd3 peerURLs=http://192.168.2.215:2380 clientURLs=http://192.168.2.215:2379 isLeader=false

看到Leader从etcd3转移到etcd1
查看集群状态
$ etcdctl cluster-health
member 59b0ee3829e2b866 is healthy: got healthy result from http://192.168.2.214:2379
member a8b07bac1693e30e is healthy: got healthy result from http://192.168.2.213:2379
failed to check the health of member cf682ab5655702b8 on http://192.168.2.215:2379: Get http://192.168.2.215:2379/health: dial tcp 192.168.2.215:2379: connect: connection refused
member cf682ab5655702b8 is unreachable: [http://192.168.2.215:2379] are all unreachable
cluster is healthy
看到etcd3连接失败 这个时候在执行如下命令进行测试 发现请求正常
$ etcdctl get /demo
hello etcd
启动故障节点之后检查 集群状态恢复
$ etcdctl cluster-health
member 59b0ee3829e2b866 is healthy: got healthy result from http://192.168.2.214:2379
member a8b07bac1693e30e is healthy: got healthy result from http://192.168.2.213:2379
member cf682ab5655702b8 is healthy: got healthy result from http://192.168.2.215:2379
cluster is healthy

etcd