论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
应用中心
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
qidao123.com技术社区-IT企服评测·应用市场
»
论坛
›
中间件
›
中间件
›
记一次.NET内存居高不下排查解决与启示
记一次.NET内存居高不下排查解决与启示
万万哇
论坛元老
|
2025-3-4 08:29:07
|
显示全部楼层
|
阅读模式
楼主
主题
1768
|
帖子
1768
|
积分
5304
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
前情
我们有个海外的项目,一共70个服务,前前后后花了超过一年时间完成了云服务迁移和架构调整。主要是架构调整了,原来的docker swarm托管服务,几台云服务器将n个服务堆在一起,只会对服务器资源做整体监控,服务器没事没人管单个服务的内存情况。新架构对单个服务改动不大,但外部相关架构则改头换面了,最大的改动是容器改为Kubernetes托管,放在AWS的EKS上。新架构在新的云服务上线后,袒露了很多内存题目。在此拿某个服务根据解决过程,给个排查思绪,盼望能给到大家一点启示。
题目
服务为一个普通的ASP.NET Core gRPC工程,平常没什么流量。
HPA
设置的最大副本数为5,生产情况服务启动后,Pod内存到达或超过K8s内存哀求值(512Mi),自动触发扩展到5个实例,即副本数到达最大。这与QA情况表现并不一样,也就没有在测试阶段发现。需要想办法复现、排查解决高副本和高内存占用题目。
部署里面对容器的资源,容器资源只做了对CPU和内存的预留设置(request),没有做上限设置(llimit)。从内存曲线上看,很多副本的内存甚至超过了哀求的512Mi。不过有一点很奇怪,服务的接口并没有出现性能下降的迹象。
题目复现
尝试在QA情况对相关接口进行压测,题目能复现,表现为HPA副本扩展后各个POD的内存居高不下,维持在500~600Mi长时间不释放,偶然候压测甚至能冲到800Mi。即使没有什么接口哀求,也需要超过20个小时才缓慢下降到350Mi左右。但尝试本地VS诊断工具则并没有发现什么内存不释放题目,除了一些个大对象驻留题目。
代码与dotnet-dump
因为其他类似的服务并不会这样,以是第一时间猜疑是代码题目,但这么想是错的,下面交代。猜疑代码题目后,想着是不是有什么内存走漏,找了个服务的接口在QA压测后题目能复现(即内存长时间不释放)。看了好几遍代码,除了一些个ToList用的太过频仍并没什么题目(也与内存题目不相关),用VS诊断工具查抄内存有运行又没内存泄露题目。于是在QA情况用dotnet-dump把内存快照下载返来分析,找到了个大对象堆LOH驻留范例的类,而且VS诊断工具找到的类是同一个,接着定位到了接口调用这个类的地方。业务调用很单纯,这个类就从数据库用Dapper查出来得到列表,然后分组计算下数据,不会有什么内存泄露的机会;但注释掉此部分查询则内存不再上升到500~600Mi,只在300Mi左右,而且内存使用率下降也变快了。继续二分法+注释大法调试,最后只保留数据库查询语句而不做后续业务处理惩罚,连引用都不做,内存还是会到达500~600Mi。这就让人摸不着头脑了,代码肯定是相关的,数据库查询几下一列表数据都能让内存到达预留临界值(request),列表也才约11000条数据,固然确实是LOH对象,但不至于造成这么严重的内存不释放现象。
GC调参
代码摸不着头脑,就想办法调试下GC。
方案一: 定时调用GC.Collect来回收垃圾
加入定时执行GC.Collect()后,内存占用能立即回落,这方案似乎也可以
方案二:GC配置调整:配置内存限制感知-DOTNET_GCHeapHardLimit
添加情况变量DOTNET_GCHeapHardLimit=0x20000000 # 512Mi的十六进制值,能限制内存的使用,但并不能让GC能敏感地进行回收,方案失败
方案三:切换为GC场景范例到工作站
原默以为Server GC,指定为Workstation GC后,内存占用不到180Mi,扩容缩容正常,这方案看起来也可以
调试竣事,方案一和方案三似乎可行,查了相关资料后,两个方案其实都有题目。方案一是代码自动强制执行了垃圾回收,但大多数情况下并不被建议在代码里面去执行,因为执行GC.Collect多多少少会影响服务性能,GC本身能感知内存使用率然后自动进行执行回收。至于方案三,不同的模式原来就对应着不同的服务场景,服务本身就是后端接口,切换为工作站模式大概可行,但ASP.NET Core默认就是Server GC,Server GC模式本身为了支持高性能并不会频仍执行垃圾回收(从.NET 9开始不一样,.NET 9的ASP.NET Core默认是
第三种模式
,.NET 8也支持这种模式,只不过不是默认的)。
为容器限定内存上限
查资料过程中才相识K8s的资源设置是有预留设置(request,又称哀求设置)和上限设置(limit),服务只设置了哀求request部分,没有limit部分,那有没有可能是服务容器因为没有被设置内存limit,导致GC如脱缰野马般豪气地使用内存呢?那为啥内存不释放?就是Server GC感觉内存还是够用的,具体文章参考:
工作站和服务器垃圾回收
和
动态适应应用程序大小 (DATAS)
。先查询下可用内存吧,于是加个下面接口查询:
app.MapGet("/runtime/memory", () =>
{
return GC.GetGCMemoryInfo().TotalAvailableMemoryBytes.ToString("N0");
});
复制代码
结果返回:
可用内存居然高达4Gi,真相很接近了。接着为服务设置内存limit为512Mi,再次查询得到可用内存为512Mi。没错!就是少设置了内存上限,没有这个,此时可用内存为节点内存(4GB);加了limit重新压测,曲线:
变乱如下:
程序内存释放正常!副本数释放也正常!另外接口相应时间没有受到影响,题目得到解决!
总结
服务内存曲线高居不下是因为容器没有被限制内存,K8s没有指定内存limit,可用内存就是节点/宿主机的物理内存,高达4GB。没有设置内存limit,但是设置了HPA,于是服务一启动经过一些时间内存超过HPA阈值造成副本数增加;GC默认是Server GC,其感知的内存足够以是不释放(包括小对象和大对象)。固然自动调用GC.Collect则可以释放,但一般不会这样做,因为GC有本身的一套逻辑。限定内存为0.5Gi后,内存释放曲线正常,HPA扩缩正常,相应时间正常,题目得到解决,也能解释服务的接口并没有出现性能下降的的现象。
启示
如果碰到类似内存居高不下题目,先确定.NET版本极其GC是Server GC还是Workstation GC。然后再确定其分配的可用内存是多少,K8s下要查抄其资源limit有没有被设置。如果被设置之后依然有内存不释放/泄露题目,再猜疑代码题目。
参考:
为容器和 Pod 分配内存资源
Pod 和容器的资源管理
为 Pod 配置服务质量
工作站和服务器垃圾回收
内存没有被回收
动态适应应用程序大小 (DATAS)
相识 Fargate Pod 配置详细信息
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
万万哇
论坛元老
这个人很懒什么都没写!
楼主热帖
markdown day 01
Linux系统调用四、lseek()函数详解 ...
Nacos注册中心-----从0开始搭建和使用 ...
ClickHouse(05)ClickHouse数据类型详解 ...
基于CSDN云和docker全家桶的微服务项目 ...
【云原生】Docker 进阶 -- 数据卷使用 ...
100天精通Python(进阶篇)——第39天 ...
应急救灾物资行业标准与规范 ...
阿里云域名购买流程以及免费证书的申请 ...
读Java性能权威指南(第2版)笔记02_ J ...
标签云
国产数据库
集成商
AI
运维
CIO
存储
服务器
快速回复
返回顶部
返回列表