发生背景
- pod内存使用率过高需要自动重启pod防止被kill影响线上业务
- 制定计算规则
- 首先制定的规则:
(container_memory_usage_bytes - container_memory_cache) / memory_limit > 90
- container_memory_usage_bytes和container_memory_cache是Cadvisor中采集的数据,和memory_limit不是一个采集器收集上来的,标签不一致没办法计算,所以有了如下改版进行,标签选择使前后的指标的标签一致
- 进行标签选择之后的规则
sum(container_memory_usage_bytes{container!="", container!="POD"} - container_memory_cache{container!="", container!="POD"}) by(env, namespace, pod, container) / on(pod, container, env, namespace) label_replace(label_replace(memory_limit{status=~"Running.*"}, "pod", "$1", "pod_name", "(.+)"), "container", "$1", "container_name", "(.+)") * 100 != +inf > 90
- 因为进行env, namespace, pod, container标签筛选之后能够确定只有一条指标,所以算出来的数据判断是没有问题的,该计算指标就上线了
问题伊始
- 某天下午突然一个线上环境触发了大量的pod重启,原因是因为pod内存过高导致触发了pod的自动重启,但是排查发现那一时刻的Pod内存使用率没有任何问题的,于是就来排查是否是告警误报导致的
- 经过排查发现了有同事给一个机器打了一个label,然后导致Cadvisor五分钟左右收集上来的数据存在两条基本一致的监控数据,唯一的区别是一个带新增的label,一个不带,然后我们的计算规则是sum的,这样就导致了监控指标计算出来的数值是实际的两倍大,从而触发了大量的pod重启
根因分析
- 虽然是因为node上打标签导致存在了两个类似的指标,但这只是诱因,归根结底还是因为sum函数的使用有问题
- sum函数是用来求和的,by只是相当于一个维度筛选器(These operators can either be used to aggregate over all label dimensions or preserve distinct dimensions by including a without or by clause.[摘自官网]),所以我们在使用sum的时候如果不是要使用他的聚合功能,就一定要保证by聚合之后的数据只有一条.
解决方案:
- 修改指标为
sum(container_memory_usage_bytes{container!="", container!="POD"} - container_memory_cache{container!="", container!="POD"}) by(env, namespace, pod, container) / count(container_memory_usage_bytes{container!="", container!="POD"} - container_memory_cache{container!="", container!="POD"}) by(env, namespace, pod, container) / on(pod, container, env, namespace) label_replace(label_replace(memory_limit{status=~"Running.*"}, "pod", "$1", "pod_name", "(.+)"), "container", "$1", "container_name", "(.+)") * 100 != +inf > 90
这样就能保证哪怕短时间内出现数据重合也能保证数据的稳定性 - 另外的方式就是将sum函数变更为max函数,因为env, namespace, pod, container四个维度基本已经决定了只有一条数据,如果出现特殊情况我们就以最大的值来进行计算就好了
prometheus官方文档函数描述地址