查看原文
其他

Kubernetes 数据库 Etcd 日常运维及技巧

作者:徐亚松
地址:http://www.xuyasong.com/?p=1983


etcd 是基于 raft算法的分布式键值数据库,生来就为集群化而设计的,由于Raft算法在做决策时需要超半数节点的投票,所以etcd集群一般推荐奇数节点,如3、5或者7个节点构成一个集群。

以上是etcd集群部署的共识,但是还需要注意以下问题:

一、Etcd选主过程

etcd 是高可用的,允许部分机器故障,以标准的3 节点etcd 集群,容忍1台机器宕机,下面以最简单的leader宕机来演示raft 的投票逻辑,以实际的运行日志来验证并理解。更多的场景可以看之前的原理解析

场景:正常运行的三台etcd:100、101、102。当前任期为 7,leader 为 101机器。使101 宕机

宕机前:101 为 leader,3 个 member

宕机后:102 成为新 leader,2 个 member

选举过程:

将 101 机器的 etcd 停止,此时只剩 2 台,但总数为 3。

1、101停止etcd 的运行

2、102(91d63231b87fadda) 收到消息,发现101(8a4bb0af2f19bd46)心跳超时,于是发起了新一轮选举,任期为 7+1=8

91d63231b87fadda [term 7] received MsgTimeoutNow from 8a4bb0af2f19bd46 and starts an election to get leadership.

3、102(91d63231b87fadda)成为新一任的候选人,然后自己投给了自己,获得 1 票;

91d63231b87fadda became candidate at term 891d63231b87fadda received MsgVoteResp from 91d63231b87fadda at term 8

4、102(91d63231b87fadda)发送给 挂掉的101 和 另一个100,希望他们也投给自己;

91d63231b87fadda [logterm: 7, index: 4340153] sent MsgVote request to 8a4bb0af2f19bd46 at term 8
91d63231b87fadda [logterm: 7, index: 4340153] sent MsgVote request to 9feab580a25dd270 at term 8

5、102 肯定收不到 101 的回应,因为 101 已经挂掉;

etcd[24203]: lost the TCP streaming connection with peer 8a4bb0af2f19bd46 (stream MsgApp v2 reader)

6、100 (9feab580a25dd270)收到了 102 的拉票消息,因为任期 8 大于当前100机器所处的 7,于是知道是发起了新的一轮选举,因此回应 101,我给你投票。这里任期term是关键,也就是说,100 和 102 谁先感受到 101 宕机,发起投票,谁就是新的 leader,这个也和进程初始的启动时间有关。

9feab580a25dd270 [term: 7] received a MsgVote message with higher term from 91d63231b87fadda [term: 8]
9feab580a25dd270 became follower at term 8
9feab580a25dd270 [logterm: 7, index: 4340153, vote: 0] cast MsgVote for 91d63231b8
9feab580a25dd270 elected leader 91d63231b87fadda at term 8

7、102 获得了 2 票,一票是自己,一票是 100,超过半数,成为新的 leader。任期为 8;

91d63231b87fadda elected leader 91d63231b87fadda at term 8
  • 更换完成。

二、Etcd集群必须是奇数节点吗?

etcd官方推荐3、5、7个节点,虽然raft算法也是半数以上投票才能有 leader,但奇数只是推荐,其实偶数也是可以的。如 2、4、8个节点。分情况说明:

  • 1 个节点:就是单实例,没有集群概念,不做讨论;

  • 2 个节点:是集群,但没人会这么配,这里说点废话:双节点的etcd能启动,启动时也能有主,可以正常提供服务,但是一台挂掉之后,就选不出主了,因为他只能拿到1票,剩下的那台也无法提供服务,也就是双节点无容错能力,不要使用。

2节点正常运行:

1台宕机后:

  • 3 节点:标准的3 节点etcd 集群只能容忍1台机器宕机,挂掉 1 台的逻辑上边已经演示过,如果再挂 1 台,就和 2节点的情形一致了,一直选,一直增加任期,但就是选不出来,服务也就不可用了;

  • 4 节点:最大容忍1 台

  • 5 节点:最大容忍 2 台

  • 6 节点:最大容忍 2 台

你会发现偶数节点虽然多了一台机器,但是容错能力是一样的,也就是说,你可以设置偶数节点,但没增加什么能力,还浪费了一台机器。同时etcd 是通过复制数据给所有节点来达到一致性,因此偶数的多一台机器增加不了性能,反而会拉低写入速度。

三、Etcd集群机器越多越好吗?

etcd 集群是一个 Raft Group,没有 shared。所以它的极限有两部分,一是单机的容量限制,内存和磁盘;二是网络开销,每次 Raft 操作需要所有节点参与,每一次写操作需要集群中大多数节点将日志落盘成功后,Leader 节点才能修改内部状态机,并将结果返回给客户端。因此节点越多性能越低,所以扩展很多 etcd 节点是没有意义的,一般是 3、5、7, 7 个也足够了。

在 k8s 中一般是3*master机器做高可用,也就是 3节点的 etcd。也有人将 etcd独立于 k8s集群之外,来更好地扩展 etcd 集群,或者根据 k8s 的资源来拆分 etcd,如 events 放在单独的 etcd 集群中。不同的副本数视业务规模而定,3,5,7 都可以。

四、Etcd有脑裂问题吗?

集群化的软件总会提到脑裂问题,如ElasticSearch、Zookeeper集群,脑裂就是同一个集群中的不同节点,对于集群的状态有了不一样的理解。

etcd 中有没有脑裂问题?答案是:没有

The majority side becomes the available cluster and the minority side is unavailable; there is no “split-brain” in etcd.

以网络分区导致脑裂为例,一开始有5个节点, Node 5 为 Leader。

由于出现网络故障,124 成为一个分区,35 成为一个分区, Node 5 的 leader 任期还没结束的一段时间内,仍然认为自己是当前leader,但是此时另外一边的分区,因为124无法连接 5,于是选出了新的leader 1,网络分区形成。

35分区是否可用?如果写入了1而读取了 5,是否会读取旧数据(stale read)?

答:35分区属于少数派,被认为是异常节点,无法执行写操作。写入 1 的可以成功,并在网络分区恢复后,35 因为任期旧,会自动成为 follower,异常期间的新数据也会从 1 同步给 35。

而 5 的读请求也会失败,etcd 通过ReadIndex、Lease read保证线性一致读,即节点5在处理读请求时,首先需要与集群多数节点确认自己依然是Leader并查询 commit index,5做不到多数节点确认,因此读失败。

因此 etcd 不存在脑裂问题。线性一致读的内容下面会提到。

五、Etcd是强一致性吗?

是强一致性,读和写都可以保证线性一致,关于一致性的分析可以看 这篇文章

线性一致读

线性一致性读需要在所有节点走一遍确认,查询速度会有所降低,要开启线性一致性读,在不同的 client是有所区别的:

  • v2 版本:通过 sdk访问时,quorum=true 的时候读取是线性一致的,通过etcdctl访问时,该参数默认为true。

  • v3 版本:通过 sdk访问时,WithSerializable=true 的时候读取是线性一致的,通过etcdctl访问时consistency=“l”表示线性(默认为 l,非线性为 s)

为了保证线性一致性读,早期的 etcd(_etcd v3.0 _)对所有的读写请求都会走一遍 Raft 协议来满足强一致性。然而通常在现实使用中,读请求占了 etcd 所有请求中的绝大部分,如果每次读请求都要走一遍 raft 协议落盘,etcd 性能将非常差。

因此在 etcd v3.1 版本中优化了读请求(PR#6275),使用的方法满足一个简单的策略:每次读操作时记录此时集群的 commit index,当状态机的 apply index 大于或者等于 commit index 时即可返回数据。由于此时状态机已经把读请求所要读的 commit index 对应的日志进行了 apply 操作,符合线性一致读的要求,便可返回此时读到的结果。

六、Etcd集群部署

简单介绍下 etcd 的安装过程。下载 etcd3.4 的 release 包。

1、生成证书

1.1 ca-config.json

创建用来生成 CA 文件的 JSON 配置文件,这个文件后面会被各种组件使用,包括了证书过期时间的配置,expiry字段:

{ "signing": { "default": { "expiry": "87600h" }, "profiles": { "demo": { "usages": [ "signing", "key encipherment", "server auth", "client auth" ], "expiry": "87600h" } } }}

1.2 ca-csr.json

创建用来生成 CA 证书签名请求(CSR)的 JSON 配置文件:

{ "CN": "demo", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "demo", "OU": "cloudnative" } ]}

1.3 生成基础 ca 证书

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

执行后会生成三个文件:

  • ca.csr:证书签名请求,一般用于提供给证书颁发机构,自签就不需要了

  • ca.pem:证书,公共证书

  • ca-key.pem:CA密钥

1.4 生成 etcd 证书

增加etcd-csr.json文件,ip 需要填写三台 etcd 机器的 ip:

{ "CN": "demo", "hosts": [ "127.0.0.1", "ip1","ip2","ip3" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "demo", "OU": "cloudnative" } ]}

这里的hosts字段中指定了授权使用该证书的IP和域名列表,因为现在要生成的证书需要被etcd集群各个节点使用,所以这里指定了各个节点的IP。

生成证书:

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=jpaas etcd-csr.json | cfssljson -bare etcd

创建etcd 的 CA 证书:这里需要4 个文件

  • etcd-csr.json:etcd的证书配置

  • ca.pem:基础公钥

  • ca-key.pem:基础私钥

  • ca-config.json:配置文件,如过期时间

执行后会生成三个文件:

  • etcd.csr

  • etcd.pem

  • etcd-key.pem

在一台机器上做证书生成,生成后将这三个文件拷贝到其他几台机器。

2、部署集群

etcd 启动配置示例:

./etcd \--name=etcd-0 \--client-cert-auth=true \--cert-file=/etc/etcd/ssl/etcd.pem \--key-file=/etc/etcd/ssl/etcd-key.pem \--peer-cert-file=/etc/etcd/ssl/etcd.pem \--peer-key-file=/etc/etcd/ssl/etcd-key.pem \--trusted-ca-file=/etc/etcd/ssl/ca.pem \--peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \--initial-advertise-peer-urls https://100.0.0.0:2380 \--listen-peer-urls https://100.0.0.0:2380 \--listen-client-urls https://100.0.0.0:2379,https://127.0.0.1:2379 \--advertise-client-urls https://100.0.0.0:2379 \--initial-cluster-token etcd-cluster \--initial-cluster etcd-0=https://100.0.0.0:2380,etcd-1=https://100.0.0.1:2380,etcd-2=https://100.0.0.2:2380 \--initial-cluster-state new \--quota-backend-bytes=8589934592 \--auto-compaction-retention=10 \--enable-pprof=true \--data-dir=/var/lib/etcd

3、etcdctl命令

因为etcd配置了证书,所以所有的命令都要带上证书访问,如:

ETCDCTL_API=3 ./etcdctl --endpoints=https://0:2379,https://1:2379,https://2:2379 --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem endpoint status --write-out=table
  • version: 查看版本

  • member list: 查看节点

  • endpoint status: 节点状态,leader 情况

  • endpoint health: 健康状态与耗时

  • set app demo: 写入

  • get app: 获取

  • update app demo1:更新

  • rm app: 删除

  • mkdir demo 创建文件夹

  • rmdir dir 删除文件夹

  • backup 备份

  • watch key 监测 key 变化

  • get / –prefix –keys-only: 查看所有 key

- END -

推荐阅

Kubernetes CKA官方认证(K8s运维工程师)

Kubernetes 容器云平台技术方案

全网最详细的 K8s Service 不能访问排查流程

QPS、TPS、并发用户数、吞吐量关系

Linux服务器被入侵后的处理过程

DevOps精神:谁开发,谁负责

企业 MySQL 优化实施方案

疫情之下,人人都需要一技傍身,是时候拿下K8s了



年轻时偷的懒,迟早是要还的。点亮

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存