假设你已经通过kubeadm 安装好了K8S 和对应的etcd集群
成都创新互联公司-专业网站定制、快速模板网站建设、高性价比梧州网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式梧州网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖梧州地区。费用合理售后完善,十余年实体公司更值得信赖。
Kubenretes1.6中使用etcd V3版本的API,使用etcdctl直接ls的话只能看到/kube-centos一个路径。需要在命令前加上ETCDCTL_API=3这个环境变量才能看到kuberentes在etcd中保存的数据。
如果是使用 kubeadm 创建的集群,在 Kubenretes 1.11 中,etcd 默认使用 tls ,这时你可以在 master 节点上使用以下命令来访问 etcd :
-w指定输出格式
将得到这样的json的结果:
使用--prefix可以看到所有的子目录,如查看集群中的namespace:
输出结果中可以看到所有的namespace。
key的值是经过base64编码,需要解码后才能看到实际值,如:
etcd中kubernetes的元数据
我们使用kubectl命令获取的kubernetes的对象状态实际上是保存在etcd中的,使用下面的脚本可以获取etcd中的所有kubernetes对象的key:
注意,我们使用了ETCD v3版本的客户端命令来访问etcd。
通过输出的结果我们可以看到kubernetes的原数据是按何种结构包括在kuberentes中的,输出结果如下所示:
我们可以看到所有的Kuberentes的所有元数据都保存在/registry目录下,下一层就是API对象类型(复数形式),再下一层是namespace,最后一层是对象的名字。
以下是etcd中存储的kubernetes所有的元数据类型:
转自
etcd是典型的读多写少存储。
在etcd v3.4.9版本中,etcdctl是通过clientv3库中访问ectd server的, client v3库基于gRPC client API封装了操作etcd KVServer、Cluster、
Auth、Lease、Watch等模块的API,同时包含了负载均衡、健康探测和故障切换等特性。
负载均衡算法:
etcd通过拦截器提供了丰富的metrics、日志、请求行为检查等机制,可记录所有请求的执行耗时及错误码、来源IP等,也可控制请求是否允许通过。
etcd 实现了一些特性:
串行读过程:
client发送请求到etcd server--Leader 节点收到请求之后,持久化到WAL日志--广播给各个节点,等到一半以上节点上持久化成功--将请求标记为已提交
--ectd server 模块异步从Raft模块获取已提交的日志条目,应用到状态机。
线性读是通过ReadIndex机制保证数据一致性原理。
线性读过程:
KVServer模块收到线性读请求后,向Raft模块发起ReadIndex请求,Raft模块将Leader最新的已提交日志索引封装在ReadState结构块,通过channel
层层返回给线性读模块,线性读模块等待本节点状态机追赶上Leader进度,追赶完成后,通知KVServer模块,与状态机中的MVCC模块进行交互。
串行读具有低延时、高吞吐量的特点,适合对数据一致性要求不高的场景。
线性读解决读数据一致性要求高的场景。
MVCC的核心由内存树形索引模块和嵌入式的KV持久化存储库boltdb组成。
boltdb是基于B+ tree实现的k-v键值库,支持事物,提供GET/PUT等简易API给etcd操作。
etcd如何基于boltdb保存一个key的多个版本:
treeIndex是基于btree实现的。treeIndex模块只会保存用户的key和用户版本号信息,用户的key的value数据存储在boltdb里面。
从treeIndex模块中获取hello这个key对应的版本号信息,treeIndex模块基于B-tree快速查找此key, 返回此key对应的索引项keyIndex即可。
获取版本号之后,可以从boltdb模块中获取用户的key-value数据了。在访问boltdb前,首先会从一个内存读事物buffer中,
二分查找要访问key是否存在,如果命中则直接返回。
boltdb是使用bucket隔离集群元数据和用户数据,bucket就是MySQL的一个表,用户的key数据存放真的bucket名字的是key,
etcd MVCC元数据存放的bucket是meta。
Getting Started with Kubernetes | etcd
etcdserver:mvcc:database space exceeded错误:
etcd server收到put/txn等写请求的时候,会首先检查当前etcd db大小加上请求的key-value大小只是否超过了配额。
如果超过配额,会产生一个告警请求,告警类型为NO SPACE,并通过Raft日志同步给其他节点,告知db无空间,并将告警持久化
到db中。
etcd设置建议配额不超过8G。APPLY模块在执行每个命令的时候,都会去检查当前是否存在NO SPACE告警,如果有则拒绝写入。
在调大配额之后,需要发送一个取消告警的命令,以消除所有告警。
检查etcd的压缩是否开启、配置是否合理。在配置etcd db配额,就不要设置小于0的,这样是禁用配额功能。
为了保证集群稳定性,避免雪崩,任何提交到raft模块的请求,都会做一些简单的限速判断。
在经过检查之后,会生成一个唯一的ID,将此请求关联到一个对应的消息通知channel,然后raft模块发起Propose一个提案,向raft模块发起的提案后,
KVServer模块会等待此put请求,等待写入结果通过消息通知channel返回或者超时。etcd默认超时时间是7秒,如果一个请求超时未返回结果,则可能会出现你熟悉的
Raft模块收到提案后,如果当前节点是Follower,它会转发给Leader,只有Leader才能处理写请求,Leader收到提案后,通过Raft模块输出待转发给Follower
节点的消息和待持久化的日志条目。
etcdserver 从Raft模块获取到以上消息和日志条目后,作为Leader,它会将put提案消息广播给集群各个节点,同时需要把集群Leader任期号、投票信息、
以提交索引、提案内容持久化到一个WAL日志文件中,用于保证集群的一致性,可恢复性。
WAL记录是按照顺序追加写入组成,每个记录由类型(Type)、数据(Data)、循环冗余校验码(CRC)组成。
WAL记录类型目前支持5种,分别是文件元数据记录、日志条目记录、状态信息记录、CRC记录、快照记录:
WAL模块是如何持久化一个put提案的日志条目记录:
每个提案被提交前都会被持久化到WAL文件中,以保证集群的一致性和可恢复性。
etcd的幂等性是根据Raft日志条目中的索引字段。etcd通过引入consistent index字段,来存储系统当前已经执行过的日志条目索引,实现幂等性。
Apply模块基于consistent index和事务实现了幂等性。
MVCC主要是由两部分组成,一个是内存索引模块treeIndex,保存key的历史版本信息,另一个是boltdb模块,用来持久化存储key-value数据。
版本号在etcd里面发挥着重大作用,它是etcd的逻辑时钟。etcd启动的时候默认版本号是1,从最小值1开始枚举到最大值,未读到数据的数据则结束,最后读出来的
版本号即时当前etcd的最大版本号currentRevision。
boltdb是一个基于B+tree实现的key-value嵌入式db,通过提供桶机制实现类似于MySQL表的逻辑隔离。
将修改的数据放入到一个名为key的桶里,在启动etcd时自动创建。
boltdb value的值是将包含key名称、key创建是时版本号、最后一次修改的版本号、修改菜蔬、value值、租赁信息序列化为二进制数据。
etcd使用合并再合并解决写性能差的问题:
etcd在启动时候通过mmap机制将etcd db文件映射到etcd进程地址空间,并设置mmap的MAP_POPULATE flag,它会告诉Linux内核预读文件,Linux就会将文件内容
拷贝到物理内存中,此时会产生磁盘I/O。节点在内存足够的请求下,后续处理读请求过程中就不会产生磁盘I/O了。
如果etcd节点内存不足时,可能会导致db文件对应的内存页被换出,当读请求命中的文件未在内存中时,就会产生缺页异常,导致读过程中产生磁盘IO,
可以通过观察etcd进程
可以通过观察etcd进程的majflt字段来判断etcd是否产生了主缺页中断。
V2版本的key在etcd是按照目录格式来存储的:
对于createdIndex 和 modifiedIndex两个值,基本上是一直相等的,当你-XPUT的时候,会同步更新这两个值,但delete和update的时候这两个值就会不同了,只有modifiedIndex会增加。
etcd的回复里面,包含了简单的消息头,里面的数据也比较重要。
数据读取比较简单,直接读取某个key就可以。
和设置一样,更改的时候用也是PUT操作
TTL就是给key设置一个timeout,时间到了之后,key会被自动删除,当然你可以在超时之前删除timeout,这样key就不会有超期了。同样的你也可以不断的去刷新key的timeout,这样可以起到看门狗的作用(可以用来探测etcd的存活)。
需要注意的一点是,timeout只会由leader来触发,如果一个instance(不是leader)因为某种原因退出集群了,那么该instance的超时key就不会删除了,除非它重新加入集群,leader会帮它删掉(个人认为这时候不再是timeout删除,而是raft底层的数据同步,会把删除操作append到节点,节点会删除数据.如果leader退出了,那么新的leader会执行timeout操作。
上面说过,在超时之前可以用命令重新更新key的ttl。
watch功能是etcd里面一个很重要的功能,现在有v2和v3两个版本。分别对应了不同的设计,可以参照下面的链接:
我们可以通过常轮训来监听key的变化,同时可以使用 recursive=true 参数来对子key(目录)监听。
注意:
etcd的watch智能保持100条记录(V2版本,v3没这个限制),所以收到通知之后应该将response交给其它线程去处理,不要在watch线程里处理,不然容易阻塞!!
前面已经说过etcd的v2版本只能保存1000个事件,如果已经事件丢失,我们需要先得到目前的状态,然后再开始监听。比如我们对一个key设置了2000次,那么etcd里面保存的直邮1000-2000的事件,如果这时候我们用下面命令:
那现在我们怎么开始监听这个key那,因为我们也不知道etcd里面保存的事件是从哪里开始的。所以我们可以使用下面命令得到etcd现在的状态。
前面已经解释过返回的信息的标志位的意思了。X-Etcd-Index代表的是etcd的状态,modifiedIndex代表的是上次修改这个key的index,X-Etcd-Index是大于等于modifiedIndex的,理论上来讲用两个index + 1是相同效果,但是用modifiedIndex可能会导致上面说的401error,所以我们一般都用X-Etcd-Index。
连接关闭指的是可能server还没来的及发送event,但由于超时或者server发生了关机,因为http的header是一旦接收到连接就会返回头部的,所以返回值会是200:ok和空的消息体。client需要自己处理这种情况。
在一个目录下使用POST可以创建出顺序的key,有时候这个功能很有用,比如需要严格按照顺序处理的事件。可以保证cleint可以公平的访问mutex锁(这个点没太搞懂)
创建一个顺序的key很简单:
这里的key的后缀是全局的etcd的index。
etcd的存储是以目录树的结构来的,所以我们可以对某个目录设置一个TTL。
目录的ttl超时的时候,如果有监听线程正在监听它下面的key,那么watch会收到一个expire的事件。
etcd主要通过三个标志位来对etcd的数据进行原子操作,注意etcd的原子操作只能针对key,不能针对目录,否则会返回102“Not a file” error。
1.prevValue - 检查key的上一个状态.
2.prevIndex -检查key的modifiedIndex.(保证没别的线程修改过)
3.prevExist - 如果是true,代表"update"请求,否则是create请求。
下面看几个例子:
etcd的删除操作也支持原子操作,标志位和上面的比少了prevExist。其它的是一样的。看例子:
在大多数情况下,目录都会在创建key的时候自动创建,但有时候我们需要自己去创建一个目录或者删除一个目录。用参数 dir=true 就可以了。
在etcd中,如果想获得目录下所有的key,可以用下面的命令:
如果没有recursive,那么只会显示目录,不会现在目录下面的key或者子目录。
删除etcd的目录的时候,如果目录下面有key或者别的目录存在,你删除的时候会返回下面的错误:
所以如果想 直接删除整个目录,可以用下面的命令(recursive=true) :
etcd可以通过添加_前缀创建隐藏的key或者目录,这时候你通过GET指令是看不到这个node的。
etcd隐藏的node主要作用是为了安全性,特地去github上看了一下作者的解释。
就是说隐藏key你通过etcd的api是看不到的,除非你能登陆本地的disk,然后查看本地的存储文件。保密性高,我们可以将我们一些key放在里面。创建的指令如下:
我们可以用etcd存储一些小的配置文件。
大家都知道etcd的写操作是都要经过raft协议同步的,线性化读取也是同样的道理。如果 Get的时候使用参数 quorum=true ,那么GET操作也要走raft协议,不是本地直接返回。
我们可以查看etcd的一些内部统计信息来观察etcd的状态。主要就分为etcd的状态和存储状态。
每个标志位的含义:
etcd的存储的状态是存储在内存中的,所以重启之后是会重置各个参数。
掌握etcd的API是使用etcd的前提条件,所以把v2版本的按照个人理解和操作整理出来。后面会整理v3版本的API。
键值存储仓库,用于配置共享和服务发现。
扩展知识:etcd(读作 et-see-dee)是一种开源的分布式统一键值存储,用于分布式系统或计算机集群的共享配置、服务发现和的调度协调。etcd 有助于促进更加安全的自动更新,协调向主机调度的工作,并帮助设置容器的覆盖网络。
etcd 是许多其他项目的核心组件。最值得注意的是,它是 Kubernetes 的首要数据存储,也是容器编排的实际标准系统。使用 etcd, 云原生应用可以保持更为一致的运行时间,而且在个别服务器发生故障时也能正常工作。应用从 etcd 读取数据并写入到其中;通过分散配置数据,为节点配置提供冗余和弹性。