1. etcd介绍

1.1 简介

etcd是一个键值存储仓库,用于配置共享和服务发现。etcd在使用中可作为一个高可用强一致性的服务发现存储仓库。 etcd作为一个高可用键值存储系统,天生就是为集群化而设计的。由于Raft算法在做决策时需要多数节点的投票,所以etcd一般部署集群推荐奇数个节点,推荐的数量为3、5或者7个节点构成一个集群。

etcd包含以下特点:

  • 简单:基于HTTP+JSON的API让你用curl就可以轻松使用。
  • 安全:支持SSL证书认证机制。
  • 快速: 官方提供的数据
  • 可靠:采用Raft算法,实现分布式系统数据的可用性和一致性。
  • 数据持久化:默认数据一更新就进行持久化。
  • Raft算法:工程上使用较为广泛的强一致性、去中心化、高可用的分布式协议。Raft是一个共识算法(consensus algorithm),所谓共识,就是多个节点对某个事情达成一致的看法,即使是在部分节点故障、网络延时、网络分割的情况下。

    1.2 基础知识

    每个 etcd cluster 都是有若干个 member 组成的,每个 member 是一个独立运行的 etcd 实例,单台机器上可以运行多个 member。 在正常运行的状态下,集群中会有一个 leader,其余的 member 都是 followers。leader 向 followers 同步日志,保证数据在各个 member 都有副本。leader 还会定时向所有的 member 发送心跳报文,如果在规定的时间里 follower 没有收到心跳,就会重新进行选举。 客户端所有的请求都会先发送给 leader,leader 向所有的 followers 同步日志,等收到超过半数的确认后就把该日志存储到磁盘,并返回响应客户端。 每个 etcd 服务有三大主要部分组成:raft 实现、WAL 日志存储、数据的存储和索引。WAL 会在本地磁盘(就是之前提到的 --data-dir)上存储日志内容(wal file)和快照(snapshot)。

    1.3 etcd的核心组件

    从 etcd 的架构图中我们可以看到,etcd 主要分为四个部分。

  • HTTP Server:用于处理用户发送的 API 请求以及其它 etcd 节点的同步与心跳信息请求。
  • Store:用于处理 etcd 支持的各类功能的事务,包括数据索引、节点状态变更、监控与反馈、事件处理与执行等等,是 etcd 对用户提供的大多数 API 功能的具体实现。
  • Raft:Raft 强一致性算法的具体实现,是 etcd 的核心。
  • WAL:Write Ahead Log(预写式日志),是 etcd 的数据存储方式。除了在内存中存有所有数据的状态以及节点的索引以外,etcd 就通过 WAL 进行持久化存储。WAL 中,所有的数据提交前都会事先记录日志。Snapshot 是为了防止数据过多而进行的状态快照;Entry 表示存储的具体日志内容。
  • 通常,一个用户的请求发送过来,会经由 HTTP Server 转发给 Store 进行具体的事务处理,如果涉及到节点的修改,则交给 Raft 模块进行状态的变更、日志的记录,然后再同步给别的 etcd 节点以确认数据提交,最后进行数据的提交,再次同步。

    1.4 读写数据

    为了保证数据的强一致性,etcd集群中所有的数据流向都是一个方向,从 Leader (主节点)流向 Follower,也就是所有 Follower 的数据必须与 Leader 保持一致,如果不一致会被覆盖。 简单点说就是,用户可以对etcd集群中的所有节点进行读写,读取非常简单因为每个节点保存的数据是强一致的。对于写入来说,如果写入请求来自Leader节点即可直接写入然后Leader节点会把写入分发给所有Follower;如果写入请求来自其他Follower节点,那么写入请求会给转发给Leader节点,由Leader节点写入之后再分发给集群上的所有其他节点。

    1.5 选举Leader节点

    Raft算法使用随机Timer来初始化Leader选举流程。 假设集群中有三个节点,每个节点上都运行了Timer(每个Timer的持续时间是随机的),第一个节点率先完成了Timer,随后它就会向其他两个节点发送成为Leader的请求,其他节点接收到请求后会以投票回应然后第一个节点被选举为Leader。

    Leader 会定时向所有的 member 发送心跳报文,如果在规定的时间里 Follower 没有收到心跳,就会重新进行选举。

    1.6 是否成功写入

    etcd认为写入请求被Leader节点处理并分发给了多数节点后,就是一个成功的写入。如何界定多数节点呢?很简单,假设总结点数是N,那么多数节点就是 >= N/2+1

    此特性是由于Raft算法在做决策时需要多数节点的投票,所以etcd一般部署集群推荐奇数个节点,推荐的数量为3、5或者7个节点构成一个集群。

    2. Linux下载安装

    两种下载方法:

    wget https://github.com/etcd-io/etcd/releases/download/v3.2.32/etcd-v3.2.32-linux-amd64.tar.gz
    curl -L https://github.com/etcd-io/etcd/releases/download/v3.2.32/etcd-v3.2.32-linux-amd64.tar.gz -o /opt/etcd-v3.2.32-linux-amd64.tar.gz
    
    tar -zxvf etcd-v3.2.32-linux-amd64.tar.gz
    
    etcd 为服务端执行文件
    etcdctl 为客户端执行文件
    

    3. 单机模式启动

    /opt/etcd-v3.2.32-linux-amd64/etcd --data-dir=default.etcd --name default \ --initial-advertise-peer-urls http://ip:2380 --listen-peer-urls http://ip:2380 \ --advertise-client-urls http://ip:2379 --listen-client-urls http://ip:2379

    etcd启动后在端口2379上监听客户端通信,在端口2380上监听服器到服务之间的通信。

    执行命令测试

    执行客户端命令前需要指定使用哪个版本的api
    export ETCDCTL_API=3
    ./etcdctl put mykey "this is a test"
    ./etcdctl get mykey
    

    4. 指定各集群成员的方式配置集群

    创建执行文件

    touch etcd-static.sh
    

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

    # 指定集群token
    # 如果你所在的网络环境配置了多个etcd集群,为了避免意外发生,最好使用-initial-cluster-token参数为每个集群单独配置一个token认证。这样就可以确保每个集群和集群的成员都拥有独特的ID。
    TOKEN=token-01
    CLUSTER_STATE=new
    NAME_1=machine-1
    NAME_2=machine-2
    NAME_3=machine-3
    HOST_1=192.168.199.140
    HOST_2=192.168.199.141
    HOST_3=192.168.199.142
    CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
    

    每个节点添加一下各节点对应启动命令行

    THIS_NAME=${NAME_1}
    THIS_IP=${HOST_1}
    /opt/etcd-v3.2.32-linux-amd64/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}
    THIS_NAME=${NAME_2}
    THIS_IP=${HOST_2}
    /opt/etcd-v3.2.32-linux-amd64/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}
    THIS_NAME=${NAME_3}
    THIS_IP=${HOST_3}
    /opt/etcd-v3.2.32-linux-amd64/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}
    

    后台启动服务:

    nohup sh etcd-static.sh &
    

    5. 使用discovery service的方式配置集群

    如果你本地没有可用的etcd集群,etcd官网提供了一个可以公网访问的etcd存储地址。你可以通过如下命令得到etcd服务的目录,并把它作为--discovery参数使用。
    执行:curl 'https://discovery.etcd.io/new?size=3'
    输出:https://discovery.etcd.io/d343fbdbc42552549ec02c2710cdca2c
    

    执行得到的输出内容作为-discovery参数使用

    同样的,当你完成了集群的初始化后,这些信息就失去了作用。当你需要增加节点时,需要使用etcdctl来进行操作。为了安全,请务必每次启动新etcd集群时,都使用新的discovery token进行注册。 另外,如果你初始化时启动的节点超过了指定的数量,多余的节点会自动转化为Proxy模式的etcd。

    创建执行文件

    touch etcd-dynamic.sh
    

    每个节点如下配置

    # 指定集群token
    # 如果你所在的网络环境配置了多个etcd集群,为了避免意外发生,最好使用-initial-cluster-token参数为每个集群单独配置一个token认证。这样就可以确保每个集群和集群的成员都拥有独特的ID。
    TOKEN=token-01
    CLUSTER_STATE=new
    DISCOVERY=https://discovery.etcd.io/d343fbdbc42552549ec02c2710cdca2c
    THIS_NAME=节点自己的名称
    THIS_IP=节点自己的host
    /opt/etcd-v3.2.32-linux-amd64/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}
    

    后台启动服务:

    nohup sh etcd-dynamic.sh &
    

    6. 常用参数说明

    --name:方便理解的节点名称,默认为default,在集群中应该保持唯一,可以使用hostname。

    --data-dir:数据保存的目录,默认为${name}.etcd。

    --snapshot-count:最大快照次数,指定有多少事务(transaction)被提交时,触发截取快照保存到磁盘,默认值100000。

    --max-snapshots: 最大保留快照数,默认 5 个。

    --heartbeat-interval:心跳周期,leader 多久发送一次心跳到 followers。默认值是100ms。

    --eletion-timeout:重新投票的超时时间,如果follow在该时间间隔没有收到心跳包,会触发重新投票,默认为1000ms。

    --listen-peer-urls:和同伴通信的地址,比如http://ip:2380,如果有多个,使用逗号分隔。需要所有节点都能够访问,所以不要使用localhost!

    --initial-advertise-peer-urls:该节点同伴监听地址,这个值会告诉集群中其他节点。

    --listen-client-urls:对外提供服务的地址:比如 http://ip:2379,http://127.0.0.1:2379,客户端会连接到这里和etcd交互。

    --advertise-client-urls:对外公告的该节点客户端监听地址,这个值会告诉集群中其他节点。

    --initial-cluster:集群中所有节点的信息,格式为 node1=http://ip1:2380,node2=http://ip2:2380,…。注意:这里的node1是节点的 --name 指定的名字;后面的 ip1:2380 是 --initial-advertise-peer-urls 指定的值。

    --initial-cluster-state:新建集群的时候,这个值为 new;假如已经存在的集群,这个值为 existing。

    --initial-cluster-token:创建集群的 token,这个值每个集群保持唯一。这样的话,如果你要重新创建集群,即使配置和之前一样,也会再次生成新的集群和节点 uuid;否则会导致多个集群之间的冲突,造成未知的错误。

    --log-level: 日志等级。info, warn, error, panic, or fatal。

    所有以 --init 开头的配置都是在 bootstrap 集群的时候才会用到,后续节点的重启会被忽略。

    7. 集群模式下客户端命令行

    执行客户端命令前需要指定使用哪个版本的api

    export ETCDCTL_API=3
    
  • 获取集群节点
  • ./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 member list
    加上参数:--write-out=table,可以以表的形式输出
    
  • 查看节点状态
  • ./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 endpoint status --write-out=table
    
  • 向集群中设置值
  • ./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 put key "value"
    
  • 获取集群中的值
  • ./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 get key
    可以跟参数:--prefix,获取所有有相同前缀的数据
    
  • 删除集群中数据
  • ./etcdctl --endpoints=192.168.199.140:2379,192.168.199.141:2379,192.168.199.142:2379 del key
    可以跟参数:--prefix,删除所有有相同前缀的数据
    

    8. etcd-manager安装

    官网下载安装包安装

    https://etcdmanager.io/