前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >K8S内存消耗,到底该看哪个图?

K8S内存消耗,到底该看哪个图?

作者头像
HelloMin
发布2022-08-11 15:18:14
4.4K2
发布2022-08-11 15:18:14
举报
文章被收录于专栏:Pair ProgrammingPair Programming

最近的一项工作,是查看服务在过去一段时间的内存实际使用量,给K8S平台上的POD内存设置一个基于历史数据的合理上限,既不会限制服务的正常运行,也可以尽量减少不必要的占坑。

本来是一个很简单的工作,按理说看看图,确定下最高峰的内存消耗,也就结束了。谁知这个看图的过程中看出些奇妙,事后竟花了2天的时间看了十几篇文章来研究,刚给米国的同事写了一封能翻好几页的邮件来讲这个问题,自己也总结一下。

先说奇妙。结合多个线上的监控图,我发现,使用不同的监控指标,看出来的内存使用情况差距很大。

如果用RSS作为指标,内存一直很稳定:

但是用WORKING SET作为指标,我们的内存好像一直在狂涨,而且分分钟要涨到目前的POD上限...

那么问题就来了,我们到底应该看哪个指标,来确定POD内存的使用上限呢?

故事一开始,还得从Linux讲起。Linux支持给不同的进程划分Cgroup,也就是拉小群,一个群里的进程共享本群的资源,包括内存CPU等等,Docker底层就是用了Cgroup来达到容器的资源控制。

划分了Cgroup来给不同的进程做资源隔离之后,Linux本身就提供了很多指标,来展示Cgroup内的内存使用情况,这里我们比较关心的值有:

代码语言:javascript
复制
$ cat /sys/fs/cgroup/memory/memory.stat 
cache xxx 
rss xxx
inactive_file xxx
active_file xxx


上面四个值中:

cache自然指的是缓存,包括文件缓存

rss指的是常驻内存,是分配给进程使用的实际物理内存,包括进程使用的栈内存,堆内存,以及共享库的内存

inactive_file和active_file,按照我的理解都是文件缓存,两者的区别是,一个文件第一次被访问,会算做inactive file, 被访问了两次之后,就会从inactive file的小队,归到active file的小队。

到了K8S这边,为了用户监控POD的内存消耗,K8S层面也暴露了很多不同的内存指标,我们这里比较关心的是:

代码语言:javascript
复制
container_memory_cache -- 缓存占用的大小
container_memory_rss -- RSS占用的大小
container_memory_usage_bytes -- 当前使用内存,包括所有内存,不管有没有被访问
container_memory_working_set_bytes -- 当前内存工作集使用量

从K8S的源码可以看出,K8S的指标,实际上就是对上面Linux的指标做了一些计算之后得出的:

RSS的计算方式很直观,就是读取了total rss:

代码语言:javascript
复制
ret.Memory.RSS = s.MemoryStats.Stats["total_rss"]

WORKING SET的计算方式则是K8S自创的,用的是usage减去inactive file:

代码语言:javascript
复制
inactiveFileKeyName := "total_inactive_file"
if cgroups.IsCgroup2UnifiedMode() {
 inactiveFileKeyName = "inactive_file"
}
workingSet := ret.Memory.Usage
if v, ok := s.MemoryStats.Stats[inactiveFileKeyName]; ok {
if workingSet < v {
  workingSet = 0
 } else {
  workingSet -= v
 }
}
ret.Memory.WorkingSet = workingSet

从上面可以看出,我们关心的两个指标的来源是不同的:RSS只关心进程实际使用的内存,但是WORKING SET还把active file也算进去了,也就是说,文件缓存这部分也算进去了。

那下一个问题就是,K8S OOM的标准到底是什么?按理说,文件缓存既然是缓存,到了危机时刻,内存压力山大的时候,文件缓存都该让位给进程,这部分缓存应该都是可以写回磁盘,腾出地方来给进程使用的。

但是实际情况是,当缓存占用的空间巨大时,K8S会认为内存达到上限直接杀掉POD重新调度。这个问题在Github上提了个Issue,总有人发现自己POD的RSS很低,Cache很大的时候,也被K8S杀掉了:

这个Issue从2017年被人发现,直到四天前还有人在回,可见也是一个老毛病了...但至少可以得出结论,缓存所占的内存也是会导致OOM的。

在浏览了各种Issue之后我发现,K8S考虑缓存也许不是没有理由的。在另一个Issue中,有人也遇到类似的坑,最后发现,不是所有的底层文件系统都能支持Dirty文件缓存写回的。那要是要的时候缓存不肯让座儿,进程本身又要更多内存,那可不就,全玩儿完...

综上,虽然文件缓存确实应该不算在进程使用的内存中,但是在K8S上,很显然它的存在对于POD的生死是有决定性的影响的。综上,我认为监测WORKING SET是更符合实际情况的,我们这里的内存上涨也是需要被关注的。

就是这样。

疫情期间上班抢菜已经费尽所有脑力,但还是想好好搞清楚一个问题,也许这就是死理性派的小执着吧...

祝你五一快乐!

Schönes Wochenende!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Pair Programming 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档