容器内微服务OOM问题排查及解决
背景
问题现象:测试环境,有一个功能的所有接口请求超时,查看微服务下的日志,发现OOM了
问题环境:Kubernetes环境,微服务部署在pod的容器中
问题排查
1、环境出现问题时,首先查看服务日志,发现OOM了:
2、发生OOM时,会在容器内自动生成一个hprof快照文件,立马拷贝到宿主机(pod重启后会丢失),然后再拷贝到本机:
3、在本机使用JProfiler打开快照文件,首先查看堆内存中类的大小排序:
4、看到了一个熟悉的实体类,初步怀疑有可能是这个实体类占用内存太多导致的。点开"最大对象",会发现最大的两个分别是ArrayList和Mongo对象:
5、选定对象后,查看两个大对象中的内容,分别为:
ArrayList对象:
Mongo对象:
6、通过以上信息,基本可以判断是查询mongo中的app_ids_info_rule_details表时,返回了大量的SysRuleDetailDO对象导致的
7、将这两个对象在图表中显示,可以看到是哪一行代码进行的mongo查询:
8、找到对应代码:
9、找相关同学了解,发现出现OOM问题前,有大量的客户端多次调用查询系统规则详情的接口,这样就会在极短时间内大量的查询mongo库的操作,导致内存中有大量的该对象
解决方案
通过了解发现:
- 每次查询规则数据后,会在内存中进行大量的计算,最终得到一个很简单的数据结构然后返回给客户端。
- 每次导入规则数据后,服务端会收到规则变化的回调消息
对于上面的两点,可以发现很好的优化点:
- 额外增加一张表,当收到规则变化的回调消息时,提前计算后需要返回给客户端的数据,并保存到数据库
- 为了进一步提升性能,还可以加一个本地缓存
- 收到规则回调消息后,先写入缓存,再入库
- 客户端查询规则,先查询缓存,没有命中再查库,然后再刷新缓存
知识改变世界