zkcrescent 的木屋

Etcd

Etcd

官方定义: 为共享配置服务发现而生的高可用键值存储

A highly-available key value store for shared configuration and service discovery.

架构

ARCH

说明

  • HTTP SERVER: 用户交互API
  • RAFT : 强一致性算法,同步各个节点的数据状态
  • STORE: 数据处理,监控,反馈,事件处理和执行等,ETCD对用户提供的大多数API的具体实现
  • WAL: Write Ahead Log(预写式日志),etcd的数据存储方式,所有提交都会先预写

通常,用户提交请求从HTTP SERVER转发给STORE处理事务,如果涉及节点修改,则交给RAFT进行状态变更的记录,然后同步给其他ETCD节点,最后进行数据提交,再次进行同步

因为 raft 采用的是投票选举 leader 的方式,所以建议节点采用奇数个节点作为集群节点有利于投票产生结果

对 etcd 实际使用实践不做累述,参考官方和各大文章即可

etcd v3 重要变更(部分)

  1. IANA 认证端口 2379(CS),2380(NN)
  2. 任何节点proxy请求到leader使得可以通过任意节点对整个集群的数据进行操作
  3. 任一节点监听多个广播地址
  4. 节点拥有独立ID,分辨请求
  5. 启动配置固定,节点变化可以在运行时变动
  6. raft 重写,日志严格使用wal,CRC校验(循环冗余校验)
  7. 配置可通过环境变量

Term

  • Raft: etcd 采用的分布式系统强一致性算法
  • Node: raft 状态实例
  • Member: 一个etcd实例,管理一个Node和提供api 服务
  • Peer: 同一集群中另一个 member 的称呼
  • Snapshot: 防止 wal 日志过大而设置的某个时间点的数据状态快照
  • Proxy: etcd的一种模式,为 etcd 集群提供反向代理
  • Leader: Raft 中通过 vote 产生的中心处理节点
  • Follower: Raft 中 vote 失败的节点,提供强一致性保证
  • Candidate:当 Leader 心跳超时后, follower 进入 candidate 开始重新 vote 新的 leader
  • Term: Vote 开始到下次 vote 的时间叫做一个 term
  • Index: 数据编号, raft 中通过 term 和 index 定位数据

节点变更

etcd 支持运行时的节点变动(增加,删除,迁移等),此时的变更对 etcd 来说也是一次信息存储和同步,当且存在足够正常节点的情况下才能进行变动 etcd 正常运行的条件是多数节点正常工作,所以出现节点损坏时需要及时修复,同时也变相需求节点数尽可能为奇数,有利于集群情况的准确掌控

关于节点

节点数量增多会提高集群可用性,因为上文提到的 etcd的正常运行条件决定的,同时可以提高读取吞吐,但是会降低写入速度,需要参考实际情况决定数量,理论上没有上限,官方建议不要大于7,最佳实践为5个,两个容错可以支持绝大多数场景了,太多会导致写成本太大

当节点损坏时,如果存在任何数据损坏或者丢失的可能性(磁盘问题,数据过期等), 最佳操作时移除该节点,然后添加一个全新的节点

存储

etcd 存储两个部分,snapshot 和 wal,snapshot 默认10000条记录做一次 snapshot,然后删除 之前的 wal

etcd 没有固定的存储限制(包括key, value), 但是 API 有最大请求限制,默认 1.5m,可以通过参数--max-request-bytes 修改, 数据存储最大默认值为 2G,--quota-backend-bytes修改,最大建议 8G,超过会在etcd启动时给出提示,过大影响 etcd 性能

提高请求限制可以保证工作,但是对其他请求会存在潜在影响
什么影响?未知,仅从官档中看到这样的说明_(:з」∠)_

etcd 检索值的最大耗时是在读取磁盘数据上,内存检索Key是极快的,降低磁盘检索时间(也可以对应成磁盘检索次数,因为单位次数检索时间是相同的)即可有效降低检索时间

原理: v3 中,key 按 B 树存储在内存中,值按 B+树存储在硬盘中

内存中 B 树 search key 为 etcd 的 key ,树的节点信息为 revision 信息

硬盘中 B+ 树 search key 为 etcd reversion 的值,节点存放 key, value 信息

通过将数据节点大小控制为内存分页大小(一般4KB),同时内存分页大小等于硬盘块大小,每次读取硬盘是4kb的数据块而不是单个数据,读取到数据后内存中查找相应位置然后再进行下次硬盘访问或者返回结果 检索过程:

  • 内存中通过B树找到对应 KEY 的 revisions (一组 revisions,根据用户需求查找最大 revision的 value 还是固定 revision )
  • 硬盘中通过 revision 作为 search key,B+ 树查找对应 k,v 信息

Raft

怎么实现的参考网络上的文档即可不做累述,这里列举一些 raft 相关的常见问题

Raft中一个 term(任期)是什么意思?

从时间上,一个任期讲即从一次竞选开始到下一次竞选开始。
从功能上,如果 follower 接收不到 leader 节点的心跳信息,就会结束当前任期,变为 candidate 发起竞选,有助于 leader 节点故障时集群的恢复。
发起竞选投票时,任期值小的节点不会竞选成功。
如果集群不出现故障,那么一个任期将无限延续下去。
投票出现冲突也有可能直接进入下一任再次竞选。

Raft状态机是怎样切换的

  • 开始运行时,节点默认进入 follower 状态,等待 leader 发来心跳信息。
  • 若等待超时,则状态由 follower 切换到 candidate 进入下一轮 term 发起竞选,等到收到集群多数节点的投票时,该节点转变为 leader 。
  • leader 节点有可能出现网络等故障,导致别的节点发起投票成为新 term 的 leader,此时原先的老leader 节点会切换为 follower。
  • candidate 在等待其它节点投票的过程中如果发现别的节点已经竞选成功成为 leader ,也会切换为follower 节点。

如何保证最短时间内竞选出Leader,防止竞选冲突

  • candidate 状态时的 time out 是随机的,也就是说不同节点进入 term 的时间是不同的,会有一个时间差
  • 时间差内如果收到的竞选信息 term 大于自己发起的 term,并且新 term 所在节点包含所有提交过的数据,则票投给对应节点
  • 竞选只会极小可能性出现冲突(rand 值相同且同时开始竞选且两节点均完好)

同时因为投票时会校验所在节点是否数据完整,不完整的节点投票会否定,从而也防止了 candidate 在数据缺失的情况下当选 leader 污染数据

raft 某节点宕机会怎样

  • 通常情况下,剩余节点大于过半,没有任何影响
  • 如果 leader 宕机,会有 follower 收到心跳超时进入 candidate 当选 leader 重新服务

raft 为何不考虑拜占庭将军问题

  • 拜占庭将军问题中 n 个节点宕机后还能继续提供正常服务的饭不是架构总节点应当 >= 3n+1(已经被证明), 但 raft 只需要 2n + 1 个节点
  • 原因: 拜占庭问题中会出现数据欺骗的问题,而 raft 中数据都是真实的
  • candidate 竞选时会提交自己的 term 编号和最后的 index 值,这些值都是可信的,其他节点根据这些可信信息决定是否投票
  • etcd 严格限制数据都是从 leader -> follower,不会出现数据不一致

用户读取数据应该从哪个节点

  • 理论上任何一个节点均可,因为数据提交时必然通过 leader 处理后提交,经过过半的节点数据确认,不一致将会覆盖,后才算完整存储,最后再次同步给其他节点
  • 每个节点都有 raft 的准确备份,(最坏情况是数据已经提交但是节点没有完全同步),所以可以从任意节点读取

raft 性能

  • 1000 qps写入
  • 节点越多,同步会越来越慢,读取性能增强
本文由来

很久之前看过 etcd 的一些东西,但是几乎又忘了,去广州的时候遇到了相关问题,正好就整理一下常见问题