● 公司核心系统"内存泄露"排查(完结)
- 公司核心系统内存泄露排查
- 公司核心系统内存泄露排查(后续)
- 公司核心系统"内存泄露"排查(完结)
一、前言
这个问题本来不是特别亟待解决的问题,但是堵在心里实在难受,总想知其然,并知其所以然。
先说结论:不是内存泄露,是asp.net垃圾回收机制问题:默认情况下,服务器CPU内核数决定asp.net core内存垃圾回收策略
。纯属基础不扎实,凌晨写文章记录并反省。
一个月前开始分析csredis的源码,但是没有头绪。便在MacOS/windows/ubuntu测试,多次测试pub/sub均未复现,内存一直稳定在几十MB左右,并无增涨。
二、多角度测试
review了很多遍代码,都没找到问题,所以我开始了几个测试:
- 测试HttpClient;
- csredis更换为freeredis;
- 拆分Controllers,每个实例只运行一个Controller;
1. 测试HttpClient
为了能快速查看内存增涨情况,我写了个死循环异步请求HttpClient的接口,同时也使用ab进行压测。分别放到windows/ubuntu测试,发现内存确实上涨了,但是很快便稳定在一个数值,大约200MB左右。
2. csredis更换为freeredis
csredis更换为freeredis后放到生产服务器,发现还是存在内存上涨情况,dumpheap也没发现任何问题。
3.拆分Controllers,每个实例只运行一个Controller
拆分Controllers为多个实例后,放到生产服务器模拟请求,发现所有Controller都存在内存上涨情况。
这个结论就跟诡异,只有生产服务器存在内存上涨情况,我开始怀疑生产服务器的系统问题(CentOS 7.4)。
三、Google大法
多亏了Google,百度真的搜不到有用的资料。
这个人在问asp.net core在docker下的GC机制,跟我遇到的问题类似,离解决很接近了:
这个人在问asp.net core HttpClient内存泄漏问题,但是我已经排除了HttpClient问题:
四、偶然发现
这里有2个偶然发现:
- 在生产服务器测试web api的时候,另一个web api内存出现了下降的情况。这样就排除了内存泄漏,明显内存是被回收了。
- 通过Google搜到了一条 Github KestrelHttpServer 2016年.net core 1.1的issue ,my server keeps using memory at about ~0.5 Mb per minute 的描述与我的情况一致,如下图:
除了上面的偶然发现,我又看到下面有人在2017年描述的问题,发现一个很重要的提示。
- 他在给Google云上的K8S设置内存为500MB,但是asp.net core超过了这个限制并且自动重启;限制到1000MB时,进程的占用到了650MB左右就不再增加,如下图所示:
我想起来有两台服务器都在跑这个asp.net core,登录了其中一台维护时间比较长的服务器,查看了pid后,看下进程运行的时长=1760331/3600/24,大约不到21天:
ps -p $PID -o etimes
ELAPSED
1760331
查了下监控程序记录在数据库的数据,内存占用前10天左右一直在缓慢增涨,后面一直很稳定。完全符合这群老外讨论的内容,看来真相已经很接近了。
- 下面有个大神Tim Seaward回复到:
CPU核心数,对内存垃圾回收有决定性的影响
。如下图:
我在各个服务器运行Environment.ProcessorCount后,结果如下:
#测试服务器
Windows Server 2008R2 DataCenter: 4
Ubuntu 16.04: 12
MacOS: 8
#生产服务器
CentOS: 2
- Tim Seaward给出了微软官方的解释和解决方案:
- 查了Microsoft Docs相关描述如下:asp.net core默认为Server GC。两台生产服务器都是2核,所以Server GC在64位机器上的临时段默认大小为4GB。看来2核CPU、8GB内存的服务器如果业务比较多,asp.net内存真的不够用。
- Microsoft Docs在 Fundamentals of garbage collection 给出了解决方案,和上面Tim Seaward给出的方案一致,更改设置GC模式为Workstation GC。microsoft docs的标题也很羞辱——
Fundamentals
不知道是翻译为基本原理
还是基础知识
。还是怪自己基础不扎实,所有问题应该第一时间在Microsoft Docs找答案。
最后,Server GC更换为Workstation GC,微软也给出了提醒:
如果你觉得CPU使用率比内存更重要,内存比较充裕不敢随意使用CPU,Server GC更好;如果内存使用率较高、CPU使用率相对较低,想把压力分给CPU一点去更频繁GC,则Workstation GC的性能可能更高。
目前一台生产服务器2核CPU+8GB内存,内存占用<2GB,适合Server GC模式;另一台运行了GitLab等一堆业务,2核CPU+8GB内存,内存占用>5GB,显然Workstation GC模式更适合。
-------- END --------
参考资料: