Eetcd 常见问题以及解决办法

网友投稿 1353 2022-10-18

Eetcd 常见问题以及解决办法

Eetcd 常见问题以及解决办法

etcd备份存储

它主要通过snapshot去备份的,snapshot是不能很频繁去做的,因为做snapshot的时候要去锁住磁盘空间,然后做一个快照,这个时候做的任何修改都要开辟新的空间来写,也就是snapshot频繁的时候,它就快速的让你磁盘占用的空间变的非常的大。

有了wal log,那么wal log存放的是增量数据的写入日志,它们两个结合到一起就是全局。

备份方案实践

上面是社区方案里面做了增强, 比如说在每个etcd member里面,会有一个备份的客户端,是一个sidecar形式,这个sidecar会去watch etcd leader,它每30分钟去做一次snapshot,这样snapshot的频度没有那么大,30分钟的数据备份一定是不足够的,因为极端的情况下可能是29.5秒的数据全部没有了,那么怎么减少snapshot频度又可以保证数据的时效性。

在这基础之上先做snapshot,然后去监听从快照结束reversion开始监听etcd事件,也就是通过etcd的客户端去做watch,watch所有对象,所有对象修改的信息,我们都可以通过每10s一次把这些watch到的event写入到磁盘,也就是通过snapshot的方式加上event这种方式去做增强备份。

30分钟snapshot+10s一次的event,这个event是实时去监听的,每10s写入一次,这个就是增强备份方案。

增强版backup方案

当谈论etcd备份的时候,来看看现有工具是什么。那是etcdctl snapshot save,它的好处是一次性的将整个etcd dump出来,效率比较高,但是它有它的问题,比如它锁住硬盘空间导致磁盘空间暴涨,其实还有其他方法,比如watch k8s,etcd event,这样可以把集群所有的细节变动都拉下来,

对于etcd来说我们是关心所有etcd写入的event,从这个层面就可以将集群的所有变更都记录下来。

那么就可以snapshot加上一些事件驱动,去关注事件流,将这些日志存下来再回放那个的这样维护方案。

备份时间太长数据可能丢失的越多,越短导致etcd的压力大,备份的时候,时效性上来之后,它的硬盘空间磁盘碎片就多了,因为它会snapshot会锁住磁盘,那能不能做一些auto defrag,就将defrag也做成一个自动执行的命令,让它自动过段时间去清理一次磁盘。

用户在建立etcd backup对象的时候,那么backup-operator就会每隔30分钟往remote storage写一个snapshot,但是30分钟的频次是不够的,我们会导致最多30分钟的数据丢失,这是不可接受的,那我们要在原来的基础上做个增强,我们在backup的sidecar里面去写一个etcd的watch client,它去监听snapshot后面所有的时间,其实就是wal log,它其实就是监听snapshot之后的reversion所有的变更,那么每1分钟或者每10s将这种增量信息也存放到remote volume,也存放到远端存储。watch结果是什么?(比如这边更新对象,那边就会有一个put,put k=value1,value2,它就会有一个一个这样的event出来)

当去做数据的restore的时候,我先去snapshot里面拉取30分钟的频度快照,然后接下来我去remote volume里面拉取这一堆时间的增量,在原来快照的基础之上,再将这些增量replay出来,最后实现了对整个etcd的备份和恢复,即减小了snapshot的频次,又保证了数据的时效性。

安全性

数据加密

任何k8s对象在落盘的时候,本身是可以通过非对称加密的形式保存的,这样即使通过etcd这一端去做数据恢复,那么这里面的数据也是一个加密数据,你是看不到的。

有哪些对象需要加密可以通过EncryptionConfiguration里面配置,通常就是secret,因为secret往往存放着用户的密码 证书 token这些信息,它是需要安全保证的,providers这里就会提供加密算法来保存,都是非对称加密算法,这些数据一旦保存,你没有这些key是解不开的,这样就保证的数据的安全性。

查询apiserver

数据存放在etcd里面了,通过什么样的方式在apiserver这边查询呢?比如说要查询test/namespace里面所有的pod,前面api是它的前缀,v1就是group version,pod属于core group,所以group信息不需要体现,所以这里只写了一个v1。

然后查询test namespace里面所有的pod就是一个rest调用,这个rest调用最后会被转化为etcd调用。

基本上后缀都是一致的。

etcd里面有reversion的概念,任何的对象都有一个版本信息,这个reversion信息在k8s里面它表现的行为为resource version,无论是单个的对象还是list,在去get 对象的时候可以加上watch参数,不仅仅要get还要保证长连接去watch,同时可以去指定resource version,这样就是从之前某个版本来watch,最后转化为etcd里面的请求就是加上reversion信息,这样的话你正真的watch是这个对象从你指定的reversion到当前reversion的所有变化的信息,只要没有compact,那么这些历史信息就存着,就可以返回给你。

分页查询

很多时候etcd里面存储的对象是非常多的,如果任何的查询都要将全量返回回来,你可想而知开销有多大,我们希望在做操作的时候返回output的量,在查询数据库的时候不能全量返回,要做分页查询。

那么我们去get某个对象的时候,kubelet其实默认加了一个限制,叫做limit,limit其实默认是查询500个,返回前500之后,返回的list里面会给你一个continue的token,k8s会按照这个token继续往下查下一部分。

所以做大数据查询的时候,基本上都是通过这种方式去做分页查询的,先返回500给你一个token,下次加上continue token,它就知道这次查询的时候是和上次连接起来的,它就会将下一批发送给你。

新的查询又会给你新的continue token,你带着新的continue token它就会给你返回1000-1500。

通过这样机制就做了分页查询的支持。

ResourceVersion

resource version到底怎么使用,我们任何的对象都有resource version,可以看到为204,所以单个对象的resourceversion就是对象最后修改的时间,之前说过最后修改时间就是它的mode version,这个对象会被创建,会被修改,他的mode reversion就是当这个对象修改的时候这个etcd里面reversion的增长的值,注意不同的对象的reversion是公用同一个增长序列的,这个reversion是整个集群增长的,不同的对象它的mode reversion就是它最后修改一次的reversion,这个reversion就是当你查询对象它显示的resourceversion。

再来回顾乐观锁,当两个控制器要去修改一个对象的时候,那么这两个进程拿到的是当前这个对象的mode reversion,当一个进程要去修改它,这个请求先发过去了,修改对象resourceversion也就是mode reversion,和etcd里面是一样的,这个请求被接受并且被修改了,那么这个对象的mode reversion是发生变化了的,这个时候第二个请求再发过去,它基于老的modereversion,在这个请求被etcd处理的时候他就会发现你是基于老版本,我现在已经增长了,所以你这个请求是不合法的,它就给你返回409 conflict,这个时候客户端有责任去拉去新的版本,包括新的reversion,在那个基础之上重新做修改。

如果list对象的时候,不加resource version,这就意味着告诉apiserver说我不相信你的cache,你要把最新的数据还给我,就会导致请求穿透apiserver,直接到etcd,在写代码的时候一定要注意。

当使用label去做对象过滤查询的时候,这个过滤时在apiserver做的,etcd本身是没有过滤能力的,所以apiserver依然会将全量请求发送到etcd里面,发过来以后再apiserver这边做过滤。

上面是容易出问题的点。

频繁的leader election

通过网络存储来挂载etcd member,这样减少了备份的需求,就不需要备份了,因为最少有份数据保存在网盘,最后就会发现一个member永远跟不上,跟不上就会出现问题,分裂出去了,

与apiserver之间链路阻塞

daemonset不停的去list pod导致链路阻塞,导致节点状态汇报不上来

很多问题都是在早期,后面社区恢复掉,5个节点master,把两个搞的没有响应了,当时apiservre的healthy check,它只是看etcd里面健康的,也就是2379的端口,只要这个端口还通,它就认为它是活着的,但是实际上这两个节点已经503了,它已经不能正确的响应了,只有右边的3 4 5这三个节点是正常工作的,但是apiserver看到这些,但是apiserver看到端口是通的,它就认为它是活的,apiserver这边没有反应,apiserver健康,但是连接的etcd本身已经不正常工作,那么就会有40%节点挂载在这两个apiserver上面,因为负载均衡,它们的状态上报就会经过这两个apiserver,这样状态就报告不上去,对于每个节点的kubelet来说,它认为apiserver是活着的,所以他长连接继续保持,继续状态的上报,apisever接到请求之后,写数据写不进去,后面的etcd坏了,没有能力将请求转发到leader上面了,那么这些节点的状态上报就失败了,就会导致节点掉线,集群里面有controller manager的,它认为40%节点坏了,那么就将40%节点的pod驱逐,也即是集群40%pod受影响了,这是非常严重的问题。

这是伪故障,不是节点坏了,是控制面的组件坏了,那么kubelet误认为这些节点坏了就将pod迁走了,业务就会受到剧烈的影响。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:mybatis foreach list特殊处理方式
下一篇:WEBrick- 嵌入式HTTP服务器程序库
相关文章

 发表评论

暂时没有评论,来抢沙发吧~