性能测试与调优:基准测试工具、瓶颈分析与系统调优
聊到高性能服务器,很多人第一反应是“把代码写快”。但说实话,我见过太多项目,代码写得花里胡哨,上线一压测,CPU 跑满、内存飙红、网络延迟高得离谱。嗯,性能不是“写”出来的,是“测”和“调”出来的。
这一章,我就带你走一遍我自己的调优流程。从工具到分析,再到内核参数,咱们一步步来。
基准测试工具:先摸清你的底牌
调优之前,你得知道系统现在什么水平。就像体检,先量血压再开药。我个人习惯用这三把刀:
ab(Apache Bench)
最轻量的 HTTP 压测工具。适合快速验证接口的吞吐能力。
# 100个并发,发10000个请求
ab -n 10000 -c 100 http://your-server/api
输出里重点看 Requests per second 和 Time per request。我在项目中遇到过,ab 测出来 QPS 很高,但换 wrk 一测就露馅——因为 ab 不支持长连接,测的是短连接场景。
wrk:现代压测利器
支持 Lua 脚本,能模拟复杂场景。我一般用它来测长连接和 Keep-Alive 下的性能。
wrk -t12 -c400 -d30s http://your-server/api
参数说明:12 个线程,400 个连接,持续 30 秒。输出里的 Latency 分布很重要——别只看平均值,看 P99 和 P999。
top 或 htop,观察 CPU 和内存变化。如果 CPU 没跑满但 QPS 上不去,大概率是锁竞争或 IO 瓶颈。
iperf:网络带宽测试
很多时候性能瓶颈不在应用层,而在网络层。iperf 能帮你快速定位是带宽不够还是延迟太高。
# 服务端
iperf -s -p 5001
# 客户端
iperf -c server-ip -p 5001 -t 30 -i 1
输出看 Bandwidth 和 Retransmits。重传率超过 0.1% 就要警惕了——我曾经排查过一个线上问题,应用层代码优化了好几轮都没用,最后发现是网卡队列满了,丢包严重。
性能瓶颈分析:找到那个“木桶短板”
工具只是手段,分析才是核心。我一般按这个顺序排查:
举个例子。有一次我压测一个网关服务,CPU 只用了 30%,但 QPS 就是上不去。用 perf top 一看,热点函数居然是 __lll_lock_wait——说白了,锁竞争。换成无锁队列后,QPS 直接翻倍。
CPU/内存/网络调优:动手改代码
CPU 调优
- 减少上下文切换:用
taskset绑定 CPU 核心,避免进程在核间跳来跳去。我习惯把网络线程和业务线程绑在不同的核上。 - 避免伪共享:多线程访问同一缓存行的不同变量,会导致缓存行失效。用
alignas(64)或__attribute__((aligned(64)))做缓存行对齐。 - 用 CPU 亲和性:设置
sched_setaffinity,让关键线程独占核心。
// 缓存行对齐示例
struct alignas(64) AlignedData {
int64_t counter;
// 填充到 64 字节,避免伪共享
char padding[64 - sizeof(int64_t)];
};
内存调优
- 减少动态分配:用对象池或内存池。我写过一篇笔记,用
tcmalloc替换glibc malloc,小对象分配速度提升了 3 倍。 - 利用局部性:把热数据紧凑排列。比如把频繁访问的字段放在结构体开头。
- 大页内存:对数据库或缓存服务,开启透明大页(THP)或手动配置 2MB/1GB 大页,能减少 TLB miss。
echo never > /sys/kernel/mm/transparent_hugepage/enabled。
网络调优
- 调整 socket 缓冲区:增大
tcp_rmem和tcp_wmem,减少丢包重传。 - 开启 SO_REUSEPORT:多进程监听同一端口,内核做负载均衡。我压测过一个 HTTP 服务,开启后吞吐量提升了 40%。
- 使用 epoll 而非 select/poll:这个不用多说,C++ 网络编程的常识。
内核参数优化:让操作系统为你服务
应用层代码优化到极致后,瓶颈往往在内核。以下是我常用的参数调整:
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
| net.core.somaxconn | 128 | 65535 | 监听队列长度,高并发下必须调大 |
| net.ipv4.tcp_tw_reuse | 0 | 1 | 允许重用 TIME_WAIT 状态的 socket |
| net.ipv4.tcp_fin_timeout | 60 | 15 | 减少 FIN_WAIT2 等待时间 |
| vm.swappiness | 60 | 10 | 降低 swap 使用倾向,减少磁盘 IO |
| kernel.sched_migration_cost_ns | 500000 | 5000000 | 减少 CPU 迁移频率,稳定缓存 |
# 一键应用优化参数(生产环境请逐项验证)
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_fin_timeout=15
sysctl -w vm.swappiness=10
tcp_rmem 设得太大,反而会占用过多内存,导致 OOM。我建议每次只改 1-2 个参数,压测对比后再继续。
嗯,调优这件事,说白了就是“测量-分析-修改-再测量”的循环。没有银弹,只有耐心。你想想看,一个参数调好了,QPS 涨 10%,十个参数就是翻倍——但前提是,你得知道瓶颈在哪。
我个人习惯把每次调优的参数和效果记下来,形成自己的“调优手册”。下次遇到类似场景,直接翻笔记,省时省力。