一、为什么要在Linux上跑DotNetCore应用
以前大家都觉得.NET只能活在Windows里,但自从DotNetCore横空出世,这个观念就被彻底打破了。现在很多企业选择在Linux服务器上部署DotNetCore应用,主要出于几个现实考虑:
- 成本优势:Linux服务器授权费用低,云服务商给的Linux实例价格通常比Windows便宜30%以上
- 性能表现:我们的压测数据显示,同样的硬件配置下,Linux上的Kestrel比IIS的请求处理吞吐量高出15%-20%
- 容器化友好:Linux容器镜像体积通常只有Windows的1/10,CI/CD流程更高效
不过迁移过来后,很多团队会遇到一些"水土不服"的情况。上周我就帮一个电商团队解决了他们的订单服务在Ubuntu 20.04上CPU占用率莫名飙升的问题,这类情况其实都有章可循。
二、必须掌握的Linux环境配置
2.1 系统基础调优
在部署应用前,建议先对Linux系统做这些调整(以Ubuntu为例):
# 修改文件描述符限制(解决Socket连接数问题)
sudo bash -c 'echo "* soft nofile 65535" >> /etc/security/limits.conf'
sudo bash -c 'echo "* hard nofile 65535" >> /etc/security/limits.conf'
# 调整TCP栈参数(提升网络性能)
sudo bash -c 'cat > /etc/sysctl.d/99-dotnet.conf <<EOF
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
EOF'
sudo sysctl -p /etc/sysctl.d/99-dotnet.conf
2.2 运行时优化
DotNetCore在Linux上有几个关键配置项经常被忽视:
// Program.cs 中的关键配置
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel(options =>
{
// 重要:Linux下需要显式配置线程池
options.Limits.MaxConcurrentConnections = 1000;
options.Limits.MaxConcurrentUpgradedConnections = 1000;
options.Limits.MinResponseDataRate = null; // 关闭最小传输速率限制
})
.UseStartup<Startup>();
})
// 启用Linux系统诊断器
.UseSystemd();
三、典型性能问题排查手册
3.1 CPU占用过高问题
上周遇到的典型案例:一个简单的API服务在8核机器上CPU长期保持在90%+。排查步骤:
- 先用top找到高CPU的dotnet进程PID
- 通过perf工具采集数据:
# 安装诊断工具
sudo apt install linux-tools-common
# 采集30秒数据
sudo perf collect -p <pid> -o perf.data -- sleep 30
# 生成火焰图
sudo perf script -i perf.data | stackcollapse-perf.pl | flamegraph.pl > flame.svg
分析火焰图发现是JSON序列化占用了60%的CPU,最终通过改用Source Generator解决问题:
// 旧代码(问题所在)
var json = JsonSerializer.Serialize(data);
// 优化后代码
[JsonSerializable(typeof(Order))]
internal partial class OrderContext : JsonSerializerContext {}
var json = JsonSerializer.Serialize(data, OrderContext.Default.Order);
3.2 内存泄漏排查
Linux上可以用dotnet-dump工具:
# 安装诊断工具
dotnet tool install -g dotnet-dump
# 捕获内存dump
dotnet-dump collect -p <pid>
# 分析dump文件
dotnet-dump analyze core_20230801_143050
> dumpheap -stat
> gcroot -all 00007f9d4a123456
最近遇到一个典型案例:由于未注销的事件处理器导致Dictionary不断增长。修复方案:
// 错误示例
service.OnUpdate += HandleUpdate;
// 正确做法
private void Subscribe()
{
service.OnUpdate += HandleUpdate;
}
public void Dispose()
{
service.OnUpdate -= HandleUpdate; // 必须显式注销
}
四、高级调优技巧
4.1 使用PGO优化
.NET 7引入的Profile Guided Optimization在Linux上效果显著:
# 训练阶段(收集运行时数据)
dotnet run --configuration Release --publish
# 应用阶段(使用训练数据优化)
dotnet run --configuration Release --publish --pgo
某金融项目实测数据:
- 启动时间缩短40%
- 交易处理吞吐量提升18%
4.2 内存模式选择
在docker部署时特别重要:
# Dockerfile关键配置
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
ENV COMPlus_GCHeapCount=4 # 根据CPU核心数设置
ENV COMPlus_GCHeapAffinityMask=0xF # 绑定到特定CPU
五、避坑指南
时区问题:Linux默认使用UTC,必须在Dockerfile中显式设置:
ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime文件系统差异:
- Linux区分大小写,路径中的大小写必须完全匹配
- 文件权限问题:确保wwwroot有正确权限
文化设置:
// 在Program.cs中添加 CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("zh-CN");
六、监控方案推荐
推荐组合:
- Prometheus(采集指标)
- Grafana(可视化)
- 使用
dotnet-counters实时监控:dotnet-counters monitor --process-id <pid> \ --counters Microsoft.AspNetCore.Hosting,System.Runtime
关键监控指标:
requests-per-secondgc-heap-sizethreadpool-thread-count
七、总结建议
经过数十个项目的实战验证,我总结出这些最佳实践:
- 新项目直接采用.NET 7+版本,性能优化功能更完善
- 生产环境必须配置系统诊断器(UseSystemd)
- 重要服务部署到不同可用区,通过Nginx做负载均衡
- 定期使用
dotnet-counters检查健康状态
某电商平台迁移到Linux后的数据表现:
- 服务器成本降低60%
- 平均响应时间从120ms降至85ms
- 部署时间从15分钟缩短到2分钟
记住:性能优化是个持续过程,建议每季度做一次完整的性能评估。遇到具体问题时,善用Linux的诊断工具和.NET的CLI诊断工具组合排查,往往能事半功倍。
评论