7 月性能调优清单:10 个配置改动带来的延迟下降

发布时间:2026/7/27 11:03:20
7 月性能调优清单:10 个配置改动带来的延迟下降 7 月性能调优清单10 个配置改动带来的延迟下降一、性能调优不需要大动作有时候改个参数就够了七月团队对平台上的 4 个推理服务和 6 个微服务做了一轮系统性的性能调优。最终带来延迟下降的改动有 10 项其中 7 项是配置层面的调整不需要改一行业务代码。这个事实值得关注很多性能问题的根源不在代码逻辑而在运行环境和服务配置的默认值与真实负载不匹配。下面这 10 项改动按延迟下降幅度降序排列每项都附调优前的指标、调优后的数据和配置变更。二、10 项配置改动的全景视图改动一vLLM max_num_seqs 从默认 256 调至 128P99 ↓35%vLLM 的max_num_seqs控制了单次推理可同时处理的序列数。默认值 256 在并发 100 时会导致显存带宽竞争P99 延迟飙升到 680ms。将max_num_seqs从 256 降到 128 后P99 延迟降至 440ms下降 35%。根因是减少了显存带宽的并发争抢——每个序列的 KV Cache 都需要读写显存序列数越多带宽竞争越激烈。128 是在当前 A100-80G 上测出的最优值高于它延迟开始加速上升低于它吞吐浪费。但这个值不具有普适性。如果上下文平均长度增加需要进一步降低。调优方法是在固定 QPS 下扫描 64-256 区间找到延迟和吞吐的交点。改动二GPU 显存预分配从 0.9 调至 0.85P99 ↓28%vLLM 默认使用 GPU 总显存的 90% 作为 KV Cache 池。实测 90% 时CUDA Graph 占用、驱动开销和碎片空间不足频繁触发 OOM Killer 导致 Pod 重启。降到 85% 后不仅 OOM 次数从日均 3 次降到零还因为 GC 压力减小P99 延迟下降了 28%。这 5% 的显存留给 CUDA 运行时做临时分配性价比很高。改动三启用 KV Cache FP8 量化P99 ↓22%对于 Qwen-72B 这类大模型KV Cache 容量是吞吐瓶颈。FP8 量化将 KV Cache 精度从 FP16 降到 FP8显存占用减半。效果立竿见影相同显存下可支持的 batch_size 翻倍在同等并发下 P99 延迟下降了 22%。精度损失在内部评测中 BLEU 和 ROUGE 差异 0.5%生产可接受。改动四批处理超时从 100ms 调至 30msP99 ↓18%自适应批处理引擎的默认等待窗口是 100ms——当队列中请求不足 batch_size 时最多等 100ms 再执行。在高并发场景下100ms 的等待时间直接叠加到端到端延迟上。降到 30ms 后低负载场景下可能会有少量 GPU 算力浪费batch 没填满但 P99 延迟下降了 18%。对于延迟敏感的生产服务这个 trade-off 值得。改动五启用 HTTP/2 多路复用P99 ↓15%推理网关和下游服务之间的 HTTP/1.1 连接每个请求独立握手当并发超过 500 时TCP 连接数爆炸导致 TIME_WAIT 堆积。切换到 HTTP/2 后连接数从 500 降到 8多路复用不仅降低了 CPU 开销TLS 握手次数减少P99 延迟也下降了 15%。配置改动非常简单——在 HTTP Client 初始化时设置http2.WithTransport。改动六gRPC Keepalive 参数调整P99 ↓12%内部微服务之间通过 gRPC 通信。默认的 Keepalive 配置Time: infinity, Timeout: 20s意味着连接空闲后不会主动探测如果对端崩溃客户端需要等到 TCP 超时通常 15 分钟才能发现。加上合理的 Keepalive 参数后grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 30 * time.Second, // 每 30s 发送 ping Timeout: 10 * time.Second, // ping 响应超时 PermitWithoutStream: true, // 空闲连接也发 ping })这避免了向已死连接发送请求导致的 15 分钟超时等待。P99 在节点故障场景下下降了 12%。改动七数据库连接池从无限制改为有界P99 ↓10%Pod 启动时数据库连接池无界创建高峰期 6 个 Pod 各自建立 120 个连接数据库侧连接数 720。超过 RDS 实例的max_connections: 500限制后新连接拒绝超时时间覆盖 P99。db.SetMaxOpenConns(50) // 6 Pod × 50 300留 200 余量 db.SetMaxIdleConns(20) // 空闲连接保留减少握手 db.SetConnMaxLifetime(30 * time.Minute) // 防止长连接导致的不均衡设置后的效果是两个维度P99 下降 10%数据库连接数从 720 降到 300。连接池大小公式MaxOpenConns (DB max_connections × 0.6) / Pod 数量。改动八GOMAXPROCS 与容器 CPU Limit 对齐P99 ↓8%Go 运行时默认 GOMAXPROCS 宿主机 CPU 核数。但 K8s 容器被限制为 2 核时GOMAXPROCS 仍为宿主机的 64 核。这导致 GC 时过度并行64 个 GC Worker 争抢 2 个核STW 时间从正常 2ms 延长到 15ms。使用uber-go/automaxprocs自动对齐后P99 下降 8%。这个改动一行代码import _ go.uber.org/automaxprocs改动九IO 调度器从 mq-deadline 切换到 kyberP99 ↓6%节点 NVMe 盘的 IO 调度器默认 mq-deadline在大量随机读推理服务加载模型权重场景下延迟抖动大。切换到 kyber 调度器后IO 延迟的 P99 抖动从 120ms 降到 80ms反映到端到端延迟下降 6%。改动十文件描述符上限从 1024 调至 65536OOM 次数 ↓90%默认 ulimit 1024 在生产环境严重不够——一个 Go 服务的 goroutine 网络连接、文件日志、metrics 端点等轻松超过 1024。七月有两次因为 fd 耗尽导致新连接失败表现为诡异的 EOF 错误。将 fs.file-max 调到 65536 后由 fd 耗尽导致的 OOM 风险消失服务稳定性显著提升。三、调优方法论先找瓶颈再动手七月调优最重要的经验是不要凭直觉猜测瓶颈在哪。调优前的标准做法是用火焰图找 CPU 热点如果是 CPU bound优先调算法。用perf stat看 IPC 和 cache miss如果 IPC 低且 cache miss 高瓶颈可能在内存访问模式而非配置。用 eBPF 看 IO 延迟分布区分是 IO bound 还是锁竞争。确认瓶颈类型后才决定是改配置还是改代码。七月 10 个改动中 7 个是配置调整说明团队在之前的部署中留下了大量默认值而这些默认值并不是为生产环境设计的。四、配置改动也有副作用需要明确的是每个配置调整都是 trade-off不是免费午餐。max_num_seqs降到 128 提升了延迟但吞吐上限也相应降低了约 15%。在 QPS 继续增长时需要重新评估。KV Cache FP8 量化以精度换速度对一些精度敏感的 Fine-tuning 场景如数学推理可能不适用。批处理超时降到 30ms 会导致 GPU 空转增加约 5%-8%成本会轻微上升。五、总结七月 10 项性能调优改动覆盖了推理引擎参数、网络协议、连接池、Go 运行时和操作系统五个层面。P99 延迟累计下降明显其中最大的收益来自 vLLM 的配置优化三项合计下降 50%和 Go 运行时对齐GOMAXPROCS。两条最值得推广的经验第一默认值从来不是为了生产环境设计的应该把检查所有默认配置作为服务上线的标准步骤第二性能调优要先定位瓶颈再动手盲目调参可能越调越差。基础设施需要持续迭代的优化每一次小小的改动都是对系统稳定性的一寸寸夯实。