前段时间现网某局点升级,告警服务出现 CPU跑满反复重启的问题
运维人员分析后,给的结论是某个ID的告警数量太多导致告警服务cpu耗尽,于是给这个告警添加了屏蔽规则
一周后再次升级,问题仍然没解决,局点质疑没有定位出根因
后来我开始介入问题的根因分析,我首先思考的问题是为什么告警服务会挂掉?
通过日志,我确认直接原因是livesness健康检查持续失败所以被K8S重启,那么为什么健康检查会持续失败?猜测几个原因:
1、cpu太高
2、tomcat连接耗尽
我尝试模拟重现这个问题,先尝试通过增加请求tps把cpu跑满,结果发现即使cpu跑满了,健康检查虽然会失败,但是不会一直失败,健康检查接口仍能被调度
当我再增加连接数时,发现健康检查的成功率越来越低,直到完全不能成功
所以,相比cpu,连接数耗尽更关键
通过日志,分析出几个数据:
1、从tomcat日志分析出升级期间告警服务的请求tps飙涨,从平时的不到1 tps,最高达到300+ tps,峰值持续了10多分钟
严重超过了告警服务的性能规格(100tps)
2、从运行日志分析出数量最多的告警top 10
得到上述数据后,首先我们把top10的告警发给相关的服务组,让他们去分析优化
但是这个并没有从根本解决问题,下次可能又是其他告警多,所以我们不能完全依赖于客户端侧减少告警数,还需要从服务端侧考虑流控能力
但是告警服务其实是有流控机制的,他用了一个内部的流控框架,走读代码发现这个流控是通过spring filter机制实现的,这样的流控作用有限,因为走到流控的地方时已经消耗了cpu和tcp连接了。那么是否有更好的流控方案?
我们的请求是通过iptables---haproxy---ingress---pod 进来的,可以在ingress里进行流控
尝试在ingress里加流控后,后端pod确实安全了,但是ingress的cpu占用增加了200%,因为我们是https带证书认证的,在ingress里进行证书认证很耗cpu。而且这个ingrress是很多服务共用的,如果他的cpu过高可能会影响其他服务。所以这不是一个很好的方案
其他办法?
由于告警服务在整个产品中并不是很关键的服务,在升级过程中,告警服务只要不挂掉(挂掉会导致整个管理面升级失败),他丢失部分告警是可以接受的
所以告警量大的时候,我们可以丢告警,但是不能影响健康检查。前面我们已经分析出健康检查失败主要原因是tomcat连接池耗尽,那么可以给健康检查接口单独开一个tomcat端口和连接池,这样就不会因为告警请求多导致健康检查了。按照这个方案修改后验证有效。
最后,K8S的liveness健康检查,一般我们会把健康检查接口和业务接口共用tomcat端口和连接池,这样健康检查能更好的反应pod的状态。但是对告警服务这种场景,健康检查接口使用独立端口更合适











网友评论