Etcd原理与运维

栏目: 服务器 · 发布时间: 5年前

内容简介:基于K8s之上的声明式API编程可以说Etcd起到了至关重要的作用。一方面,API Server使用了etcd的特性从而提供了订阅,选举等功能。另一方面,k8s集群的所有配置信息也都集中存放于etcd中,etcd完好的情况下,可以随意的变动node节点,k8s最终会保障服务都按照预期来编排和对外提供服务。从etcd自生的实现来讲,其使用了Raft协议来保障数据的一致性,底层使用bbolt k-v存储,同时使用WAL和snapshot等都是分布式系统研究的好素材。说到分布式系统的一致性,都会想到raft协议。

基于K8s之上的声明式API编程可以说Etcd起到了至关重要的作用。一方面,API Server使用了etcd的特性从而提供了订阅,选举等功能。另一方面,k8s集群的所有配置信息也都集中存放于etcd中,etcd完好的情况下,可以随意的变动node节点,k8s最终会保障服务都按照预期来编排和对外提供服务。

从etcd自生的实现来讲,其使用了Raft协议来保障数据的一致性,底层使用bbolt k-v存储,同时使用WAL和snapshot等都是分布式系统研究的好素材。

Raft协议

说到分布式系统的一致性,都会想到raft协议。那raft协议之所以这么声明大昭,其到底有哪些精妙之处呢?我觉得其实很多协议(包括通讯协议)都是对生活中一些道理的抽象,我后续会举一个例子来讲述raft的选举。

Raft协议主要包含两块:

  • 选举过程
    主要涉及采用何种流程来确立集群中的江湖地位;

  • 日志复制
    主要涉及在确立好各个角色江湖地位的情况下,如何保障日志存储的一致性的问题。

选举过程

无论是哪一种排别,都要先讲讲江湖地位。这里一种有三种角色,分别为:

Etcd原理与运维

  • leader

    对内,定期发送心跳报文,通告天下,维护自己的江湖地位;

    对外,负责处理所有客户端的请求,当接收到客户端的写入请求时,会在本地追加一条相应的日志,然后将其封装成消息发送到集群中其他的Follower节点。

  • candidate
    由Follower节点转换而来的,当Follower节点长时间没有收到Leader节点发送的心跳消息时,则该节点的选举计时器就会过期,同时会将自身状态转换成Candidate,发起新一轮选举。

  • follower
    简单地响应来自Leader或者Candidate的请求; 也不处理Client的请求,而是将请求重定向给集群的Leader节点。

学院派

总结起来就是:3/2/1, 即:”三个角色 / 两个定时器 / 一个任期”。

Etcd原理与运维 Etcd原理与运维

  1. 集群初始化时,所有节点都处于Follower状态, 当Follower一段时间( 选举计时器 超时)收不到Leader的心跳消息,就认为Leader出现故障导致其 任期 (Term)过期, Follower会转成Candidate;
  2. Candidate等 选举计时器 超时后,会先投自己一票,并向集群中其他节点发起选举请求,并带上自己的Term ID以及当前日志的Max Index;
  3. 如果其他节点没有投出Term ID内的一票,就会比较Candidate的Max Index是否比自己小,如果比自己大或者相等,就会投票给Candidate;同时,会将自己的 选举计时器 重置;
  4. Candidate在获取到超过半数节点的选票后,升级为Leader;并按照 心跳计时器 向集群中其他节点发送心跳报文,并同步log entity等; follower收到心跳报文后,会重置 选举计时器

注意: 在第三步中,除了要确定term任期内未投过票之外,还要确定candidate的log index的原因是保障不会让日志记录缺失的成员成为leader,相当于冒泡 排序 法,找出log最完整的成员做leader。

另外,为了保障不频繁出现重新选举,对两个定时器的设置需要满足:

广播时间 < 选举超时时间 < 平均故障间隔时间

武林派

  1. 话说当年日月圣教由任我行教主执掌,但是出于对武学的痴迷,仍教主天天闭关修炼,不理教内事务。于是教内腐败严重,没有教主的打压,各种小势力乘机崛起,其中,最牛叉的当数东方不败;
  2. 东方不败乘任教主闭关期间,怂恿半数的收下归顺自己,同时凭借自己的武功力压群雄,让教内所有人都不得不承认任我行的时期已过去,现在是东方不败的时代了;
  3. 作为新的继任者,东方不败一方面整治教内腐败,打压各种小势力;另一方面积极处理对外事务,很快教内又恢复了生机;
  4. 有一天任我行闭关归来,发现所有教众都已经诚服与东方不败;同时,功力也不如东方不败,于是也只好认栽!

这个故事歪曲了《笑傲江湖》的原剧本,谁叫任我行姓任呢,书中他必须要重出江湖呀!但是Raft协议在这里却告诉了我们什么是现实,现实就是你必须低头,你的Term过了,长江后浪推前浪。

日志复制

Leader除了向Follower发送心跳消息,还会处理客户端的请求,并将客户端的更新操作以消息(Append Entries消息)的形式发送到集群中所有的Follower。当Follower记录收到的这些消息之后,会向Leader返回相应的响应消息。 Leader在收到半数以上的 Follower的响应消息后,会对客户端的请求进行应答。

Leader会维护 nextIndex[]matchIndex[] ,这两个数组中记录的都是日志索引值

Etcd原理与运维

  • nextIndex[]

    记录了需要发送给每个Follower的下一条日志的索引值;

  • matchIndex[]

    表示记录了己经复制给每个Follower的最大的日志索引值。

调整过程

  1. 当一个新leader被选举出来时,它不知道每一个follower当前log的状态,因此会将每个的nextIndex值都设置为其日志的最大index(然后再逐步调整),同时将其matchIndex设置为0;
  2. Leader会向其他节点发送AppendEntries,若节点己经拥有了Leader的全部log(要求index和term都对应),它会返回追加成功的响应并等待后续的日志 ;若节点没有index对应的log,就会返回追加日志失败的响应;收到响应后,Leader节点会将nextIndex前移。

我的理解是,在AppendEntries中只是带了index和term信息,而不带内容;在第二步确定了nextIndex的位置之后,leader才真正将缺失的log内容追加给follower。

Etcd

主要介绍一些调试和性能方面可能有影响的知识点,以及运维常用的命令。

知识点

可能影响到etcd性能的点。

快照

etcd的members目录下可以看到snap和wal两个目录,wal下主要存放Write ahead log的数据;snap下存放的就是从wal做的snap。另外,在snap下还有一个db文件,它就是bbolt的数据库文件。

etcd会将所有变更的key追加写入到wal日志文件中。一行记录一个key的变更,因此日志会不断增长。为避免日志过大,etcd会定期做快照。快照操作会保存当前系统状态并移除旧的日志。

--snapshot-count 参数控制快照的频率,默认是 10000 ,即每10000次变更会触发一次快照操作。如果内存使用率高并且磁盘使用率高,可以尝试调低这个参数。

debug

启动参数中添加 --debug 即可打开debug模式,etcd会在 http://x.x.x.x:2379/debug 路径下输出debug信息。由于debug信息很多,会导致性能下降。

/debug/pprofgo 语言runtime的endpoint,可以用于分析CPU、heap、mutex和goroutine利用率。

调优

  • 将etcd所使用的磁盘与系统盘分开
  • data目录和wal目录分别挂载不同的磁盘
  • 有条件推荐使用SSD固态硬盘
  • 使用ionice调高etcd进程的IO优先级(这个针对etcd数据目录在系统盘的情况)
    ionice -c2 -n0 -p `pgrep etcd`
    

运维

包含一些运维常用的命令和方法,以备随时拷贝。

添加新节点

增加一个新的节点分为两步:

  1. 通过 etcdctl或对应的API注册新节点
  2. 使用恰当的参数启动新节点

假设我们要新加的节点取名为infra3, peerURLs是 http://10.0.1.13:2380

$ etcdctl member add infra3 http://10.0.1.13:2380
added member 9bf1b35fc7761a23 to cluster

ETCD_NAME="infra3"
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE=existing

etcdctl 在注册完新节点后,会返回一段提示,包含3个环境变量。然后在第二部启动新节点的时候,带上这3个环境变量即可。

$ export ETCD_NAME="infra3"
$ export ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
$ export ETCD_INITIAL_CLUSTER_STATE=existing
$ etcd -listen-client-urls http://10.0.1.13:2379 -advertise-client-urls http://10.0.1.13:2379  -listen-peer-urls http://10.0.1.13:2380 -initial-advertise-peer-urls http://10.0.1.13:2380 -data-dir %data_dir%

这样,新节点就会运行起来并且加入到已有的集群中了。

值得注意的是,如果原先的集群只有1个节点,在新节点成功启动之前,新集群并不能正确的形成。因为原先的单节点集群无法完成leader的选举。直到新节点启动完,和原先的节点建立连接以后,新集群才能正确形成。

故障恢复

备份数据

etcdctl backup --data-dir /var/lib/etcd -backup-dir /tmp/etcd_backup
tar -zcxf backup.etcd.tar.gz /tmp/etcd_backu

使用 --force-new-cluster 参数启动Etcd服务。这个参数会重置集群ID和集群的所有成员信息,其中节点的监听地址会被重置为localhost:2379, 表示集群中只有一个节点。

tar -zxvf backup.etcd.tar.gz -C /var/lib/etcd
etcd --data-dir=/var/lib/etcd --force-new-cluster ...

快照恢复

节点数据快照

ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshotdb
# exit 0

# verify the snapshot
ETCDCTL_API=3 etcdctl --write-out=table snapshot status snapshotdb
+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 |       10 |          7 | 2.1 MB     |
+----------+----------+------------+------------+

需要在每一个节点上都做restore

$ 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

存取空间限制

  • Request size limit

    etcd is designed to handle small key value pairs typical for metadata. Larger requests will work, but may increase the latency of other requests. By default, the maximum size of any request is 1.5 MiB. This limit is configurable through --max-request-bytes flag for etcd server.

    --max-request-bytes 限制请求的大小,默认值是1572864,即 1.5M 。在某些场景可能会出现请求过大导致无法写入的情况,可以调大到10485760即10M。

  • Storage size limit

    The default storage size limit is 2GB , configurable with --quota-backend-bytes flag. 8GB is a suggested maximum size for normal environments and etcd warns at startup if the configured value exceeds it.

# 设置非常小的 16MB 配额
$ etcd --quota-backend-bytes=16777216

# 消耗空间
$ while [ 1 ]; do dd if=/dev/urandom bs=1024 count=1024  | etcdctl put key  || break; done
...
Error:  rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded

# 确认配额空间被超过
$ etcdctl --write-out=table endpoint status
+----------------+------------------+-----------+---------+-----------+-----------+------------+
|    ENDPOINT    |        ID        |  VERSION  | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | bf9071f4639c75cc | 2.3.0+git | 18 MB   | true      |         2 |       3332 |
+----------------+------------------+-----------+---------+-----------+-----------+------------+

# 确认警告已发起
$ etcdctl alarm list
memberID:13803658152347727308 alarm:NOSPACE

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

金字塔原理

金字塔原理

[美] 巴巴拉·明托 / 王德忠、张珣 / 民主与建设出版社 / 2002-12 / 39.80元

《金字塔原理》是一本讲解写作逻辑与思维逻辑的读物,全书分为四个部分。 第一篇主要对金字塔原理的概念进行了解释,介绍了如何利用这一原理构建基本的金字塔结构。目的是使读者理解和运用简单文书的写作技巧。 第二篇介绍了如何深入细致地把握思维的环节,以保证使用的语句能够真实地反映希望表达的思想要点。书中列举了许多实例,突出了强迫自己进行“冷静思维”对明确表达思想的重要性。 第三篇主要针对的......一起来看看 《金字塔原理》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换