ETCD网关模式

etcd网关模式,用来构建etcd集群的门户,它是一个简单的TCP代理,可以将网络数据转发到ETCD集群。网关是无状态而且透明的,它不会检查客户端的请求,也不会干扰集群的响应,支持多个etcd服务器实例,并且采用简单的循环策略。

每个应用程序访问 etcd集群的时候,必须要要知道etcd实例的地址,如果同一个服务器上的多个应用程序访问相同的etc集群,每个应用程序仍然要知道 etcd集群的广播的客户端端点地址。如果每次重启etcd集群,就更换IP地址,应用程序就必须更改地址,容易出现问题。

使用 etcd网关作为稳定的本地端点,对于客户端应用程序来说不会感知到集群实例的变化。发生etcd集群实例的变更的时候,只需要网关更新其端点,而不需要更新应用程的代码实现。

以下场景不适用etcd网关模式:

  1. 性能提升etcd网关不是为了提高 etcd集群性能设计的,不提供缓存和批量更新的机制
  2. 在进群上运行管理系统类似k8s高级集群管理系统本身支持的服务发现。

    为了自动传播集群端点的更改,etcd网关在每台机器上都运行,为了多个应用提供访问相同的etcd集群服务。
    启动网关配置
    启动etcd网关,以通过etcd gateway命令代理这些静态端点
    etcd gateway start -- \
    endpoints=http://192.168.10.7:2370.http://192.168.10.8:2370.http://192.168.10.9:2370
    #网关模式不支持https

常用配置:

--listen-addr #绑定的接口和端口,用于接收客户端请求,默认配置127.0.0.1:2379

- retry-delay #重试连接到失败的端点延迟时间,默认1ms

-insecure-discovery #接收不安全或者容易受到中间人攻击的SRC记录,默认为fase

-trusted-ca-file #是etcd集群的客户端TLS CA文件的路径,用于端点认证

gRPC-Gateway

为非gRPC的客户端提供HTTP接口。etcd v3使用 gRPC作为消息传输协议,项目中包括了基于gRPC的Go client和命令行工具etcdctl,客户端通过gRPC框架与etcd集群通信。对于不支持gRPC客户端,使用http 转换为restful buffer的json格式。

在HTTP请求中的json兑现,其中包含的key和value字段都被定义成了byte数组。必须在JSON对象中,使用base64编码对内容进行处理。

#需要获取前缀为指定值的键值对的时候,可以使用如下请求​
curl -L http://localhost:2379/v3/kv/range ​
-X POST -d '{"key":"Zm9v","range_end":Zm9w"}'

etcd学习笔记-etcd网关与集群配置_重配置


HTTP请求客户端与etcd服务端建立长连接,当监听的键值对发生变更的时候,便会将事件通知给客户端。etcd事务的实现

事务用于完成一组操作,通过对比指定条件,成功的情况下执行响应的操作,否则回滚。

http的方式访问etcd服务端,需要考虑安全的问题,gRPC-Gateway中提供的api接口支持开启安全认证

gRPC-Gateway则是对etcd的gRPC通信协议的补充,有些语言的客户端不支持gRPC通信协议,此时就可以使用该方式对外提供HTTP API接口。

动态重配置etcd集群

在生产中,时常要增加etcd节点,移除某个etcd节点或者是更新 etcd 节点的信息,此时需要对进群进行动态重配置

集群运行时的重配置

重配置条件,只有在大多数集群成员都在正常运行的时候才进行,etcd的官方建议,在生产环境中的集群大小始终大于两个节点。

在以下场景进行动态调整

  1. 机器升级
  2. 修改集群大小
  3. 替换故障机器
  4. 重启集群

这些操作都会使用etcd 自带的etcdctl 命令行工具,命令如下所示:

etcd学习笔记-etcd网关与集群配置_客户端_02


除了使用etcdctl修改成员,还可以使用etcd v3 gRPC members API

更新成员有两种情况:

  1. client urls用于客户端的URL,也就是对外服务的URL
  2. perr urls用于监听url,与其他节点通信

    为了更新成员clent URLs,只需要使用更新后的client URL标记(即 --advertise-clietnt-urls)或者环境变量来重启这个成员(ETCD_ADVERTISE_CLETNT_URLS)
    更新peer URLs
  1. 通过成员命令更新它的
  2. 重启成员
  3. 因为更新peer URL修改了集群范围配置并能影响etcd集群的健康,所以需要找到该目标成员的ID

使用etcdctl列出成员

etcd学习笔记-etcd网关与集群配置_客户端_03


#更新8211f1d064f3269成员ID并修改它的peer URLs值的为http:/127.0.0.1:2380

etcdctl --endpoints=http://localhost:12379 \

member update 8211f1d064f326 --per-urls=httpd://127.0.0.1:2380

#显示成员

etcdctl --endpoints=http://localhost:2379 member list -w table

etcd学习笔记-etcd网关与集群配置_键值对_04


此时重启该成员,则可以重配置生效

#删除成员

etcdctl --endpinotallow=8211f1d064f3269 member remove

日志中显示打印出移除的信息

etcd学习笔记-etcd网关与集群配置_重配置_05


如果是移除leader的场景,新leader被选举的时候集群将不处于不活动状态(inactive),且持续时间通常由选举超时时间和投票过程决定。

添加新成员的过程如有如下两个步骤

  1. 通过HTTP members AP添加新成员到集群,使用gRPC members API 或者etcdctl memeber add命令
  2. 使用新的集群配置启动新成员,包括更新后的成员列表(现有成员加上新成员)

#添加成员

etcdctl --endpoints=http://localhost:22379 memeber \

add infra4 --peer-urls=http://localhost:2380

etcd学习笔记-etcd网关与集群配置_重配置_06


根据以上输出结果,直接使用etcd启动方式启动集群

etcd学习笔记-etcd网关与集群配置_客户端_07


如果添加新成员到一个节点的集群,在新成员启动前集群无法工作,因为它需要两个成员作为galosh才能在一致性上达成一致。这种情况仅会发生在etcdctl member add影响集群和新成员成功建立连接到已有成员的时间内。

运行时重配置的设计以及注意点

两阶段配置变更设计

出于安全考虑,每个etcd集群节点进行运行时重配置都必须经历两个阶段:

  1. 通知集群新配置
  2. 加入新成员

阶段1:通知集群新配置

将成员添加到 etcd集群,需要通过调用API将新成员添加到集群中。

阶段2:加入新成员

要将新的etcd成员加入集群,需要指定正确的intial-cluster,并将inital-cluster-state设置为existing

在进行集群运行重配置的时候,每一个阶段都会确认集群成员的数量和状态,在当第一阶段没有问题的时候才会进行下一阶段的操作。

集群永远失去它的大多数成员,需要从旧数据目录启动新集群来恢复之前的状态。这种情况下,极有可能从现有集群中强制删除发生故障的成员来完成恢复。

运行时重配置禁止使用公用发现服务,公用发现服务仅用于引导集群,成功引导后,成员的IP都是已知的,若要将新成员加入现有集群,需要使用运行时重新配置API

在运行时重配置会设计集群的稳定性和可用性,因此需要十分慎重,尽可能的避免运行时集群重配置。

etc集群调优

以下是ETCD简化架构图

etcd学习笔记-etcd网关与集群配置_重配置_08


流程

etcd学习笔记-etcd网关与集群配置_客户端_09


raft层是实现etcd数据一致性的关键,节点之间通过raft实现一致性通信。raft需要通过网络通信,因此网络质量和网络延迟是影响的关键因素。

storage层持久化键值对,依赖boltDB来实现wal日志和快照。磁盘的IO性能势必影响到存储层。WAL日志受到磁盘IO写入速度的影响,fdatasync延迟也会影响etcd性能。

推荐的服务器配置

etcd在开发或者测试的场景下,对硬件要求不高,而且也能运行良好。但是在实际生产环境中运行etcd集群,对于性能等方面的要求就变得很高,比如etcd集群对外提供服务时要求的高可用和可靠性。

  1. CPU要求不高,如果ETCD集群负载的客户端达到数千个,每秒请求数可能时成千上万个,这种情况下需要增加CPU的配置,通常需要8到16个专用内核。
  2. 内存etcd对内存的需求同样也不是很高,etcd服务端内存占用相对较小,对于具有数千个watch监视器或者数百万键值对的大型部署,需要将内存扩展到16GB以上。
  3. 磁盘磁盘IO速度是影响ETCD性能和稳定性的最关键因素。大多数etcd集群成员必须将请求写入磁盘,还将以增量的方式将检查点写入磁盘中,以便截断日志。如果写入花费的时间太长,那么心跳可能超时,触发选举,进而破坏集群的稳定性。可以使用基准测试工具判断磁盘的速度是否合适etcd。etcd对磁盘写入延迟非常敏感,通常需要7200RPM转速的磁盘,对于负载较重的集群,官方建议使用SSD固态硬盘。对磁盘的带宽要求不高,但是更高的磁盘带宽能够更好的在集群进行恢复。一般使用SSD作为etcd 的存储,由于 etcd的一致性复制已经获得了高可用性的,至少三个集群成员不需要RAID的镜像和磁盘阵列。
  4. 网络多个成员的etcd集群部署得益于快速可靠的网络,需要网络保证低延迟和高带宽。大型集群网络,推荐10GB带宽。通过规避在多个数据中心部署etcd成员的方式来减少网络开销,单个数据中心内部署etcd成员可以避免延迟开销。

    etcd调优
  5. 网络etcd启动时的默认设置设用于网络低延迟的场景,在网络延迟较高的场景下,如网络跨数据中心,心跳间隔和选举超时的设置就需要优化。
  6. 磁盘

etcd对磁盘的延迟非常敏感,因为etcd需要存储变更日志,多个进程同时操作磁盘可能引起更高的fsync延迟,可能会导致选举失败,集群异常等。可以优化提高etcd的磁盘进程优先级来解决

磁盘调优

磁盘优先级可以通过ionice命令来调整

etcd学习笔记-etcd网关与集群配置_重配置_10



#设置etcd进程有限使用IO资源

sudo ionice -c2 -n0 -p `pgrep etcd`


网络调优

网络延迟可能会导致follower成员与leader之间的通信请求被延迟。

etcd学习笔记-etcd网关与集群配置_重配置_11


可以通过提高leader的网络优先级来提高follower的请求响应。在linux系统中,使用流量控制机制来确定对等流量的优先级。通过tc命令能够提高leader与etcd集群成员直接按的网络优先级。

etcd学习笔记-etcd网关与集群配置_客户端_12


快照调优

etcd追加所有的键值对的变更到日志中,这些日志每一行记录一个key的变更,日志规模在不断增长。为了避免大量日志,etcd会定期生成快照。默认创建快照的配置时每1万次变更才会保存快照。如果etcd的内存和磁盘使用率过高,也可以降低这个阈值。

#调整快照

etcd --snapahot-count=5000

#或者使用环境变量的方式

ETCD_SNAPSHOT_COUNT=5000 etcd

时间参数调优

etcd实现分布式依赖两个重要的时间参数,心跳间隔和选举超时

  1. 心跳间隔用来保活,leader来通知所有的follower自己的存活时间。该参数被设置为节点之间网络往返时间,etcd默认心跳间隔时100ms
  2. 选举超时

表示,follower在多长时间没有收到leader的消息,自己会尝试自己发起选举。etcd的默认选举超时是1000ms,如果时间太长也会导致数据一致性的问题。


一个etcd集群应该设置一样的心跳间隔和选举超时,如果设置不一样,则会导致集群不稳定。

#命令行参数

etcd --heartbeat interval=100 --election-timeout=500

#环境参数

ETCD_HEARTBEATE_INTERVAL=100 ETCD_ELECTION_TIMEOUT=500 etcd

心跳间隔推荐设置为节点之间的最大RTT(Round-Trip Time 往返延迟),一般为RTT的0.5-1.5倍,过长的心跳间隔也会延长选举超时的时间。过长的心跳间隔也会延长选举超时时间。测量RTT的最简单的方法就是ping工具,基于心跳间隔和节点的平均RTT去设置。

选举超时应该至少是RTT的10倍,这样才能视为能在该网络中容错。

如果出现均匀的网络性能或者常规的网络延迟和丢失,会引起多次ETCD网络重试,所以5 s是一个安全的RTT最高值。


etcd多用于读多写少的场景,读写的开销不一样。在客户端使用etcd应该尽量避免频繁的更新键值对数据,需要多的复用lease,避免重复创建lease。对于相同TTL失效时间的键值对,绑定到相同lease租约上也可以避免大量重复创建lease.