今天的主角是CPU压缩组件,它是Go语言开发的。
CPU压缩组件是做什么的?
业务申请实例时所要的CPU配额往往比实际使用要大很多,使得K8s集群因为CPU分配率饱和无法再创建新的实例,最终导致集群的资源利用率处于非常低的水平。为了让集群的CPU分配率和CPU使用峰值更接近,更进一步提升集群整体的利用率,我们引入了CPU压缩机制。
CPU压缩组件会根据业务晚高峰的实际CPU使用动态调整实例的request,解决业务申请值和实际使用有偏差的问题。
问题描述
突然收到CPU压缩组件所在机器的内存报警。
登录机器上查看后,发现上面的两个进程的RES内存占用比较大,主要是CPU压缩进程以及Etcd server进程。
机器的内存监控大盘:
备注:
-
其实内存报警这几天有出现了3次了,评估具体影响不大,所以没有及时介入处理,前两次都是通过重启进程缓解
排查记录
优先解决问题
先进行初步的分析
进程对内存的销毁可能有哪些?
CPU压缩进程仅缓存了prometheus数据,这部分对内存的使用应该很小。
CPU压缩进程对Etcd的写入操作只有在发现实例所属的服务没有prometheus数据时才会触发,理论上这部分的QPS应该很低。
对Etcd中的数据dump处理,发现大量的分布式锁key存在,如下图所示:
key的量总共有2w个左右、key的存储量并不大,不应该是Etcd对内存占用30+G的原因,所以这里可以确定Etcd内存量增加并非是存储的数据量大引起的,怀疑是大量分布式锁key存在时,服务端需要维护很多相关对象导致内存使用增加。
确认为什么会产生这么多分布式锁key?
产生分布式锁争抢的逻辑描述如下:当Pod压缩进程遇到prometheus里没有服务数据时,会主动把该服务添加到Etcd中,这样异步拉取Prometheus数据时就会拉取该服务的数据了,由于往Etcd中写入时,为了保证操作的事务性,引入了分布式锁,避免多个Pod压缩节点之间有写入相互覆盖的情况。
因