.net 高并发服务性能瓶颈排查处理

背景

我用.net8 开发的数采和实时数据库产品在一个实际项目中遇到了性能瓶颈,表现为性能监视下网络发送流量出现断流和尖峰的情况,两个进程之间的通讯在断流时会有几秒钟的阻塞,我开始以为是网络的问题,实际是短时大量的Task阻塞了线程池,使得新的请求被迫排队等待,再就是内存开销大造成GC压力较大。

应用场景介绍

我的数采服务要从EMQX订阅数据后写入到实时数据库,数据量大约17000点/秒,每个点约30个字节,也就是510Kb数据,实际流量看数据格式,从EMQX过来的JSON格式,流量要大好几倍。

实时数据库要对外提供实时监视和历史曲线,访问频率为90次/秒,实时调用的响应很快,历史数据读取要慢一些,下面是10分钟的调用统计(Excel数据透视表)。

使用dotnet-counters+deepseek 诊断问题

可以下载一个离线dotnet-counters放到服务器的C:\Windows\System32下,然后在dos窗口中执行如下命令,注意process-id换一下

复制代码
dotnet-counters collect --process-id 12345 --format csv --output counter.csv

由于我的问题每分钟出现一两次,我抓了约1分钟数据后,直接丢给deepseek(网页)帮我分析

优化一:减少内存压力

进程收发数据时往往要new 一些集合对象,通讯结束后这些对象就不用了,使用Microsoft.Extensions.ObjectPool 在需要集合对象时Get,使用完Return可以降低这部分内存的频繁分配,结合应用场景介绍里的实时调用有多频繁,你就知道内存分配下降多明显了。

再就是,服务内部实现时,尽量避免把集合放在方法的返回值,而是作为参数,这样外部代码才能使用ObjectPool来降低集合内存分配。更进一步,还可以不适用集合,而是传入一个Action,每次迭代时调用这个Action。

复制代码
//不好的做法
public List<T> Method<T> Read(DateTime start, DateTime end)
{
    var result = new List<T>();
    //...
    return result;
}

//较好做法
public void Method<T> Read(List<T> result, DateTime start, DateTime end)
{
    //...
}

//推荐做法
public void Method<T> Read(Action<T> action, DateTime start, DateTime end)
{
    //...
}

优化二:减少大对象分配(LOH)

单个对象超过 85,000 字节会进入 LOH,LOH 不自动压缩(除非显式压缩或 Full GC),大对象分配失败会触发更昂贵的 Full GC。我在采集到数据后,会通过gRPC批量发送给Tagdb,之前设置的批上限是10000条,约300Kb,超过了85Kb,达到批量上限时发送和接收都会使用LOH,把这个改成2000条了。

优化三:并发使用Parallel.ForEach 而不是Task\[\]

在进行了前2个优化问题还在,deepseek提示线程池排队严重,"在 11:01:49 出现 ThreadPool Queue Length = 101,表明瞬时请求超过处理能力",我根据它的建议,把代码中所有Task\[\]都改成了Parallel.ForEach,options参数传入 new ParallelOptions{MaxDegreeOfParallelism = Environment.ProcessorCount},这样可以限制并发的Task数量。

我看了日志,对于脚本计算,一批数据有可能触发100个以上,之前的逻辑会一次创建这么多Task,然后WaitAll,这会使线程池排队。

优化四:自适应内存缓存

通过日志发现,某些特定功能需要定时读取超过1小时的历史数据,而我的实时数据库只在内存缓存最近1小时的历史数据,这导致较大的IO开销和CPU压力(要解压缩),我重新设计了缓存机制,根据读取来动态分配缓存,超过有效期后清除缓存,定时清理缓存中的旧数据,这样可以适应多变的用户读取行为,使服务的性能越来越好,也降低了默认1小时缓存所有点的内存占用。

效果总结

通过1周的分析和优化,网络流量规律多了,内存占用也降低了不少。

相关推荐
爱喝水的鱼丶12 小时前
SAP-ABAP:BAPI 基础认知:SAP 标准业务对象接口的核心逻辑与调用入门
信息可视化·性能优化·sap·abap·bapi·开发交流·交流学习
唐青枫19 小时前
别把 ImmutableArray 当成只读 List:C#.NET 不可变数组深入详解
c#·.net
AI服务老曹2 天前
边云协同视频分析性能优化指南:多站点部署下的资源瓶颈突破与调优实战
性能优化·音视频
微小冷2 天前
海康威视相机C#二次开发环境配置
数码相机·c#·.net·海康威视·相机开发
唐青枫2 天前
别只会解析参数:C#.NET Spectre.Console.Cli 命令行工具实战详解
c#·.net
A_cainiao_A2 天前
【ggml系列】【第五篇】ggml_compute_forward_mul_mat 矩阵乘法算子源码与性能优化深度解析
线性代数·性能优化·矩阵
ai产品老杨2 天前
边云协同视频分析性能优化指南:多站点部署下的参数配置与排查清单(边缘推理+云端管理)
性能优化·音视频
苏打水com2 天前
《llama.cpp性能优化实战:从显存、KV Cache到Token/s》
性能优化·llama
该用户可能存在2 天前
【Win11优化】StartAllBack实战:解决任务栏合并、右键折叠等痛点
windows·性能优化·win11·windows 11·startallback·任务栏·开始菜单
灯澜忆梦3 天前
【MySQL12】进阶篇 | SQL优化
数据库·sql·mysql·性能优化