• 2026年7月17日
  • 5 分钟阅读
  • SystemDo

Linux 服务器性能如何优化?指标、瓶颈定位与容量测试

从指标采集、压测工具、瓶颈定位到内核参数调整和容量基线,系统讲解企业级 Linux 服务器性能优化的工程方法。

Linux 服务器性能如何优化?指标、瓶颈定位与容量测试
SystemDo
SystemDo

软件定制开发团队

"真正有价值的技术内容,应该能帮助客户更快判断方向、预算和落地路径。"

性能优化不是调参数,而是建基线

很多运维团队接手一台慢的 Linux 服务器时,第一反应是翻网上的“性能调优清单”,把 vm.swappiness 改成 10,把 net.core.somaxconn 改成 65535,然后重启服务。这种做法偶尔能缓解症状,但往往掩盖了真正的根因。更严重的是,没有基线数据的调优等于盲调——你不知道改之前是什么状态,也无法判断改之后是否真的有效。

企业级的性能优化应该是一个闭环:采集指标 → 建立基线 → 压力测试 → 定位瓶颈 → 针对性调整 → 验证效果 → 更新基线。本文围绕这个闭环展开,不讲空洞的理论,只讲你在生产环境可以落地的方法。

指标采集:你该看什么,而不是能看什么

Linux 系统提供的指标工具非常多,但企业场景下大部分指标是冗余的。我建议只聚焦四类指标:CPU、内存、磁盘 I/O 和网络。每类指标只关注 3 到 5 个关键值,其他可以忽略。

CPU 指标

使用 `top` 或 `mpstat -P ALL 1` 观察:

  • **user% + system%**:如果持续超过 70%,说明 CPU 是瓶颈候选。
  • **iowait%**:超过 10% 说明磁盘 I/O 在拖累 CPU。
  • **steal%**:虚拟化环境下超过 5% 说明宿主机超售严重,这不是你能调的,只能迁移。
  • **load average**:超过 CPU 核心数的 1.5 倍时,系统可能已经排队严重。

一个常见的误解是只看 CPU 使用率。我曾经处理过一个案例,某 Java 应用 CPU 使用率只有 40%,但响应时间超过 3 秒。最终发现是单线程的 GC 线程频繁触发,导致应用线程被暂停。CPU 使用率不高,但 CPU 的“有效工作时间”很低。这时候你需要看 `pidstat -t -p <PID> 1` 来分辨每个线程的 CPU 消耗。

内存指标

`free -h` 和 `vmstat 1` 足够日常监控。重点关注:

  • **available**:不是 free,available 才是真正可用的内存,包括可回收的缓存。
  • **swap used**:如果 swap 使用量持续增长,说明物理内存不足。但 swap 少量使用(比如几百 MB)不一定有问题,很多系统会主动换出冷页。
  • **cache/buffer**:大文件读写的服务器,cache 占用十几 GB 是正常的,不要误判为内存泄漏。

真正危险的情况是:available 持续低于总内存的 10%,同时 swap 使用率超过 20%。这时候 OOM Killer 随时可能触发。

磁盘 I/O 指标

`iostat -x 1` 是最实用的工具。关键指标:

  • **%util**:超过 80% 说明磁盘接近饱和。但注意,NVMe SSD 的 %util 计算方式不同,100% 不一定代表饱和,需要结合 await 判断。
  • **await**:单次 I/O 请求的平均等待时间。普通 SATA SSD 应该在 1-3ms,NVMe 应该在 0.1-0.5ms。超过 10ms 说明磁盘响应慢。
  • **svctm**:服务时间,比 await 更能反映磁盘本身的性能。如果 svctm 正常但 await 高,说明 I/O 请求在排队。

我见过一个数据库服务器,%util 只有 60%,但查询非常慢。排查后发现是 RAID 卡缓存策略配置错误,写操作没有启用回写缓存。硬件层面的配置错误,软件层指标是看不出来的。

网络指标

`sar -n DEV 1` 和 `ss -s` 足够了。

  • **rxkB/s 和 txkB/s**:对比网卡带宽上限。千兆网卡持续超过 900 Mbps 时,网络就是瓶颈。
  • **drop 和 overrun**:任何非零值都说明网卡或驱动处理不过来。
  • **TIME_WAIT 连接数**:如果超过 5 万,可能需要调整内核参数或优化应用连接池。

注意:不要只看带宽,延迟和丢包率对应用的影响更大。用 `ping -c 100 -i 0.01 <目标IP>` 可以快速判断网络延迟和丢包。

压力测试:在可控范围内暴露问题

没有压力测试,你永远不知道服务器能在多高的负载下保持稳定。但压测不是随便跑一个工具看数字,而是有目的的验证。

压测工具选择

  • **CPU 压测**:`stress --cpu 4 --timeout 60s` 简单粗暴。更专业的用 `sysbench cpu run`。
  • **内存压测**:`stress --vm 2 --vm-bytes 2G`,或者 `memtester 4G 1`。
  • **磁盘 I/O 压测**:`fio` 是行业标准。关键参数:`--rw=randwrite --bs=4k --iodepth=32 --runtime=60`。一定要测试混合读写场景,因为生产环境很少只有纯读或纯写。
  • **网络压测**:`iperf3 -c <服务器IP> -P 4 -t 30` 可以测带宽。应用层的压测用 `wrk` 或 `ab`。

压测的工程原则

1. **从低到高逐步加压**:不要一上来就跑 1000 并发。从 10 并发开始,每 30 秒增加 20 个,记录每个阶段的响应时间和错误率。
2. **压测时间要足够长**:至少 15 分钟。很多问题在 5 分钟内不会暴露,比如内存泄漏、连接池耗尽、磁盘缓存写满后的性能断崖。
3. **压测环境尽量接近生产**:包括硬件配置、网络拓扑、数据量。在 8 核 16G 的测试机上压出的结果,不能直接推导到 64 核 256G 的生产环境。
4. **监控压测过程中的指标变化**:压测的同时运行 `htop`、`iostat`、`vmstat`,观察哪个指标先到达临界值。

有一次给客户做压测,应用在 500 并发时响应时间突然从 50ms 飙升到 5 秒。查看 `iostat` 发现 %util 瞬间跳到 95%,而 CPU 使用率只有 30%。根因是应用写日志的方式是同步刷盘,磁盘 I/O 成为了瓶颈。改异步日志后,同样的压测场景下响应时间稳定在 80ms 以内。

瓶颈定位:从现象到根因的排查路径

当压测或生产环境出现性能问题时,不要凭经验猜测,按照以下路径排查:

第一步:确认瓶颈层

运行 `top`,按 `1` 查看每个 CPU 的使用情况。如果所有 CPU 使用率都高,说明是 CPU 密集型问题。如果某个 CPU 使用率 100% 而其他很低,说明是单线程瓶颈。

运行 `vmstat 1`,观察 `b` 列(阻塞的进程数)。如果持续大于 0,说明进程在等待 I/O。

运行 `iostat -x 1`,观察 `%util` 和 `await`。如果 %util 高且 await 高,磁盘是瓶颈。

运行 `sar -n DEV 1`,观察 `rxkB/s` 是否接近带宽上限。

第二步:定位具体进程

使用 `top -H -p <PID>` 查看进程内的线程消耗。对于 Java 应用,可以用 `jstack` 导出线程栈,找到哪个线程在占用 CPU。

对于磁盘 I/O 问题,使用 `iotop -o` 可以实时看到哪些进程在读写磁盘。有一次排查发现 `updatedb` 进程在凌晨 3 点触发全盘扫描,导致数据库备份失败。调整 `mlocate` 的定时任务后问题解决。

第三步:分析系统调用

如果前两步找不到原因,可能是系统调用层面的问题。使用 `strace -c -p <PID>` 统计进程的系统调用分布。如果 `futex` 调用次数异常多,说明存在严重的锁竞争。如果 `write` 调用耗时很长,说明磁盘写入慢。

注意:`strace` 会大幅降低进程性能,只在测试环境或低峰期使用。

第四步:检查内核参数

很多性能问题可以通过调整内核参数缓解,但前提是你已经定位到了瓶颈层。乱调参数只会引入新问题。

内核参数调整:对症下药

以下参数调整基于实际工程经验,每个参数我都标注了适用场景和风险。

网络相关

| 参数 | 默认值 | 建议值 | 适用场景 |
|------|--------|--------|----------|
| net.core.somaxconn | 128 | 1024 | 高并发短连接服务,如 Nginx |
| net.ipv4.tcp_tw_reuse | 0 | 1 | 客户端大量 TIME_WAIT,但注意 NAT 环境下可能有问题 |
| net.ipv4.tcp_fin_timeout | 60 | 30 | 减少 TIME_WAIT 持续时间 |
| net.core.rmem_max / wmem_max | 212992 | 16777216 | 大文件传输或视频流服务 |

**风险提醒**:`tcp_tw_reuse` 只适用于客户端连接,不适用于服务端。如果服务端启用了 `tcp_tw_recycle`(Linux 4.12 之后已移除),在 NAT 环境下会导致连接异常。不要在生产环境随意启用。

内存相关

| 参数 | 默认值 | 建议值 | 适用场景 |
|------|--------|--------|----------|
| vm.swappiness | 60 | 10 | 数据库或内存敏感应用,减少换出 |
| vm.dirty_ratio | 20 | 10 | 写密集型应用,减少脏页堆积 |
| vm.dirty_background_ratio | 10 | 5 | 配合 dirty_ratio 使用,让后台写回更早触发 |

**风险提醒**:`vm.swappiness` 设为 0 在旧内核中可能导致 OOM,建议设为 1 或 10。`vm.dirty_ratio` 设得过低会导致频繁刷盘,降低写入吞吐量。

文件系统相关

  • **noatime**:挂载选项中加入 `noatime`,减少每次读取文件时的元数据写入。对数据库和静态文件服务器效果明显。
  • **deadline 或 noop 调度器**:对于 SSD,建议使用 `none`(等价于 noop)或 `deadline` 调度器,减少不必要的 I/O 重排。
  • **预读大小**:`blockdev --setra 4096 /dev/sda` 可以调整块设备的预读大小。对于顺序读密集的应用(如视频流),增大预读值可以提高吞吐量。

调整后的验证

每次调整参数后,必须重新运行压测,对比调整前后的指标变化。如果响应时间没有改善,回滚参数,继续排查其他瓶颈。不要因为参数调整了 5% 的性能就停止排查,真正的瓶颈可能还在别处。

容量基线:让性能可预测

容量基线的目的是回答三个问题:当前服务器能承受多大的负载?负载增长到多少时需要扩容?每次变更后性能是变好了还是变差了?

建立基线的步骤

1. **确定关键指标**:对于 Web 服务器,关键指标是 QPS 和响应时间。对于数据库,是 TPS 和查询延迟。对于文件服务器,是吞吐量(MB/s)和并发连接数。
2. **设定阈值**:例如,响应时间超过 200ms 视为不可接受,CPU 使用率超过 80% 视为预警。阈值应该基于业务需求,而不是技术指标。
3. **定期采集**:使用 `sar`、`Prometheus + Node Exporter` 或 `Telegraf` 采集历史数据。至少保留 30 天的数据,才能看出趋势。
4. **标注变更记录**:每次部署新版本、调整内核参数、增加用户量后,在监控系统中标注时间点。这样就能把性能变化和变更关联起来。

容量规划的经验值

以下是我在多个项目中总结的参考值,但每个业务场景不同,必须结合自身数据验证:

  • **CPU**:日常使用率不超过 60%,峰值不超过 80%。超过 80% 时,响应时间会急剧增加。
  • **内存**:available 不低于总内存的 20%。对于 Java 应用,堆外内存(Direct Buffer、线程栈)也要考虑在内。
  • **磁盘**:%util 不超过 70%,await 不超过 5ms(SSD)。
  • **网络**:带宽使用率不超过 70%,丢包率为 0。

当某个指标连续 3 天超过阈值时,就应该启动扩容计划。不要等到系统崩溃才处理。

常见误区与工程建议

误区一:追求极致的参数调优

有些团队花大量时间把 `vm.swappiness` 从 10 调到 5,把 `net.core.netdev_budget` 从 300 调到 600,试图榨干硬件性能。实际上,对于大多数企业应用,默认内核参数已经足够好。性能瓶颈通常出现在应用层、架构层或硬件层,而不是内核参数层。

**建议**:先把应用层的慢查询、不合理的连接池、无缓存的重复计算解决掉,再考虑内核调优。应用层优化带来的收益通常是 10 倍级别,内核调优最多 20%。

误区二:压测数据直接当容量规划依据

压测是在理想环境下做的,生产环境有网络抖动、其他租户争抢、突发的流量峰值。压测结果乘以 0.7 作为容量上限是比较保守的做法。

误区三:只看平均值,忽略长尾

平均响应时间 50ms 看起来很漂亮,但 P99 可能是 2 秒。对于用户体验,P99 比平均值更重要。监控系统必须采集百分位数据,不能只看平均值。

工程建议:建立性能回归测试

每次代码变更或配置变更后,跑一遍自动化压测,对比关键指标的变化。如果响应时间增加了 10% 以上,自动告警。SystemDo 在多个项目中实践过这套流程,它能有效防止性能退化悄悄进入生产环境。

总结:性能优化是持续的过程

性能优化不是一次性的项目,而是贯穿系统生命周期的持续活动。你需要建立指标采集体系,定期做压力测试,用数据而不是感觉来定位瓶颈,谨慎调整参数,并维护一份不断更新的容量基线。

最后两个原则值得记住:第一,没有基线就没有优化;第二,不要优化你测量不了的东西。把这两条贴在机房里,比任何调优清单都管用。