You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6/7 Web API简单请求下CPU近100%占用排查求助

ASP.NET Core 迁移后 Redis 相关 CPU 占用过高问题排查与解决

背景情况

  • 原服务为基于 Node.js(Express)的轻量 REST API,仅从 Redis 读取数据返回响应,高负载下 CPU 峰值可控
  • 迁移至 ASP.NET Core 后,相同负载下 CPU 占用直接翻倍,导致 AWS 自动扩容频繁触发,甚至仅达原 Node.js 服务一半负载时就触发扩容
  • 使用 StackExchange.Redis 作为 Redis 客户端,且已按最佳实践将 ConnectionMultiplexer 配置为单例实例

追踪数据分析(结合截图场景)

从提供的追踪数据来看,CPU 消耗主要集中在两个核心环节:

  1. 同步 Redis 调用导致的线程池开销:若请求处理中使用同步阻塞方式调用 Redis(如 .Wait()、.Result),会占用线程池线程,迫使线程池频繁创建新线程,带来大量上下文切换开销,直接推高 CPU
  2. 序列化/反序列化的高开销:默认序列化器(如 Newtonsoft.Json)在处理大量数据时,若未做性能优化,会产生显著的 CPU 消耗
  3. 此外,StackExchange.Redis 连接配置不合理、Redis 命令使用低效,也可能是诱因

针对性优化方案

1. 全面改用异步 Redis 操作

彻底替换同步调用为异步方法,通过 await 非阻塞调用,避免线程池资源被占用:

// 错误:同步阻塞调用
var redisValue = _redisDatabase.StringGet("user:1001").Result;

// 正确:异步非阻塞调用
var redisValue = await _redisDatabase.StringGetAsync("user:1001");

2. 优化序列化机制

替换为高性能序列化器,或调整现有序列化器的配置,减少 CPU 消耗:

  • 使用 System.Text.Json 替代 Newtonsoft.Json,并开启性能优化选项:
var jsonOptions = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    WriteIndented = false,
    ReferenceHandler = ReferenceHandler.IgnoreCycles,
    DefaultBufferSize = 1024, // 启用缓冲区池化
    AllowTrailingCommas = true
};

var userData = JsonSerializer.Deserialize<User>(redisValue.ToString(), jsonOptions);
  • 进一步优化可使用二进制序列化器(如 MessagePack),大幅降低序列化 CPU 开销

3. 调整 StackExchange.Redis 连接配置

初始化 ConnectionMultiplexer 时,优化关键参数减少不必要的开销:

var redisConfig = new ConfigurationOptions
{
    EndPoints = { "your-redis-endpoint:6379" },
    SyncTimeout = 5000, // 合理设置同步超时,避免长时间阻塞
    AsyncTimeout = 5000,
    ConnectTimeout = 10000,
    PooledSocketTimeout = 5000, // 池化套接字超时,减少连接重建
    AbortOnConnectFail = false,
    MaxIdleConnections = 10, // 配置连接池大小,避免过度创建连接
    MaxTotalConnections = 50,
    // 禁用不必要的命令追踪,减少额外开销
    CommandMap = CommandMap.Default
};

var multiplexer = ConnectionMultiplexer.Connect(redisConfig);

4. 优化 Redis 命令使用

  • 避免使用 KEYS *、SCAN 等全库遍历命令,改用前缀哈希表、有序集合等方式组织数据
  • 将多个小的 Redis 操作合并为批量命令,减少网络往返次数:
// 批量获取多个键值
var keys = new RedisKey[] { "user:1001", "user:1002", "user:1003" };
var values = await _redisDatabase.StringGetAsync(keys);

5. 启用客户端监控

通过 StackExchange.Redis 的内置事件,追踪命令执行耗时,定位具体高开销操作:

multiplexer.CommandExecuted += (sender, args) =>
{
    if (args.DurationMs > 100) // 记录耗时超过100ms的命令
    {
        Console.WriteLine($"高耗时Redis命令: {args.Command}, 耗时: {args.DurationMs}ms");
    }
};

内容的提问来源于stack exchange,提问作者Amit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:46:16