AIOps 一场颠覆传统运维的盛筵
1143
2022-11-04
应用重启元凶之Kubernetes内存单位
身处基础服务团队的好处是你不需要时刻面对业务团队频繁变更的需求,需求相对稳定,也不用花时间跟他们解释技术的原理和限制;但坏处也很明显,由于基础服务处于应用底层,你的服务有任何的变更或不稳定将会影响上游的众多业务应用。这不,前段时间就有上游应用反馈,由于连不上底层基础服务的某个实例导致他们的应用重启了。
小伙伴们在收到应用反馈后连忙跑去检查基础服务,一看,该基础服务各实例运行一切正常,运维团队也没有收到任何告警说该基础服务挂了。不过根据上游应用提供的实例名称一看,该实例确实发生过重启了。我们姑且不讨论为什么作为高可用的集群其中一个实例重启会导致上游应用重启,先把焦点放在基础服务实例为什么会重启上。这不看不知道,一看吓一跳,K8S控制台显示,过去近一个月时间该容器重启了10次,等于基本两三天就会重启,而重启原因则是OOMKilled。
OOM?内存溢出?于是我们自然而然地跑到系统监控平台上查找实例的内存使用情况,曲线非常之漂亮而且有规律,很像Java程序隔一段时间做了一次Full GC把内存回收了。但实际上它并不是JVM内存曲线,该内存曲线反映的是Docker容器的内存使用情况。由于JVM从操作系统申请了内存后,即使后面发生了GC也不会把回收的内存空间返回给操作系统,所以正常情况下该内存曲线稳定后应该是一条水平线。
放大一下曲线看谷底,我们发现内存直接降到0然后又缓慢回升,这意味着应用发生了重启。这点从上图看是比较有迷惑性的,如果不放大我们完全看不出内存曾经下降到0,上图内存最低的点也接近有1.9GiB。.
从内存监控的走势图来看,内存最多也就是用到了3.7GiB,而应用向K8S申请的最大内存是4G,都还未到OOMKilled的阈值,这是为什么呢?原因在于K8S所定义的GB并不等于计算机中的GB。
"resources": {
"limits": {
"cpu": "1",
"memory": "4G"
},
"requests": {
"cpu": "1",
"memory": "2G"
}
}
在计算机的世界里,1GB等于1024M。但在K8S的世界里,GB是gigabyte,它等于10的九次方,即1GB = 1000000000 bytes。而我们传统所认为的GB则是用GiB(gibibyte)来表示,它等于2的30次方 ,即1GiB = 1073741824 bytes。所以我们容器ymal文件里面的设置4GB换算成GiB差不多就是3.72GiB,跟内存监控里面的3.7GiB吻合。到这里,我们可以说内存单位的差异是导致应用频繁重启的原因之一。这里用了“之一”一词,皆因为内存单位的差异只是诱因,还有其它原因导致应用频繁重启,在下一篇文章将会有分析。
总结
Kubernates里面内存单位分为带i和不带i(GiB vs GB),带i的单位代表基数为1024,不带i的单位代表基数为10,我们在使用的时候需要注意这区别。
发表评论
暂时没有评论,来抢沙发吧~