ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux性能优化实战:从测量定位到内核参数调优的全流程指南

Linux性能优化实战:从测量定位到内核参数调优的全流程指南 1. 优化前先学会测量性能问题排查的整体思路提到 Linux 性能优化很多人第一反应是背一堆内核参数、抄一段 sysctl 配置。我见过不少同行把 /etc/sysctl.conf 改得花团锦簇结果业务该慢还是慢甚至更不稳。干这行久了你会发现性能优化真正难的不是知道某个参数而是先搞清楚瓶颈到底在哪再决定要不要动、动哪里。这篇文章是“Linux 性能优化”系列的开篇我会从排查思路、诊断命令、内核参数、实战案例到高频问题串起一套可落地的优化方法。不管你是刚接触 Linux 的运维新手还是被线上故障逼着查问题的后端开发都能从中找到能直接上手的思路。1.1 别急着调参先回答这几个问题接到一个“系统很卡”“CPU 高”“接口超时”的反馈我通常不立刻上服务器改参数而是先确认四个问题瓶颈在哪个维度是 CPU 跑满、内存不够、磁盘 IO 慢还是网络延迟高不同维度的解法完全不同乱调参数等于盲人摸象。是持续高负载还是偶发突刺持续高负载往往是容量或代码问题偶发突刺可能是定时任务、日志切割、缓存失效叠加造成的。业务峰值和允许的容忍度是多少优化是有成本的先确认 SLO。比如支付链路要求 p99 小于 100ms和后台报表允许跑 10 分钟完全是两个优化思路。最近有没有变更很多时候性能下降不是“慢慢变差”而是发布、扩容、配置改动后的副作用。上线前一切正常上线后 load average 一路飙升先回滚比优化参数更有效。一句话总结先定性再定位最后才谈优化。所谓“优化”是在测量之后做出的有依据的动作而不是拍脑袋写配置。1.2 建立性能基线压测与监控两手抓没有基线就没有优化。我会在系统相对空闲的时候做一轮压测把各项指标记录下来作为后续对比的基准。压测工具选择上最简单的是用stress模拟 CPU、内存和 IO 负载用sysbench测 CPU 和内存用ab、wrk、hey测 HTTP 接口。压测不是越猛越好要贴近真实业务并发数取峰值的 1.5 到 2 倍持续跑 10 到 15 分钟观察各维度监控曲线而不是只看一个瞬时值。监控方面生产环境至少要有 CPU、内存、磁盘、网络的趋势图。没有完整监控体系时可以用sar看历史采样或者临时跑一段vmstat 5 120记录两分钟快照。我自己的习惯是任何一次优化前先留一份“优化前”的 vmstat、iostat、ss 快照优化后再抓一份同样时长的数据用数字说话而不是凭感觉说“好像快了”。2. 日常诊断必备Linux 性能分析命令实战Linux 性能优化的基本功是会用命令把系统状态翻译成人话。搜“Linux 常用命令大全”的人很多但真正查性能问题时常用的其实就十几个。我把它们按使用频率分梯队讲解你可以照着边用边记。2.1 第一梯队top、vmstat、iostat、sartop是我上服务器后第一个敲的命令。肉眼看三块Load average、CPU 状态、进程列表。Load average 是 1/5/15 分钟的平均活跃进程数不是 CPU 使用率这点很多人搞混。如果 load average 持续高于 CPU 核数的 80%说明系统被压满了。CPU 状态里 us 高说明应用在计算sy 高说明内核在忙wa 高说明在等磁盘hi/si 高说明中断密集。进程列表按 CPU 或内存排序直接就能看到谁在吃资源。vmstat是更细的观察工具。命令vmstat 1 5每秒采样一次共 5 次。你重点看这几列procs 的 r运行队列长度持续大于 CPU 核数说明 CPU 饱和procs 的 b处于不可中断睡眠的进程数长期大于 0 说明有 IO 卡住swap 的 si/so每秒换入换出长期不为 0 说明内存紧张CPU 的 waIO 等待占比超过 30% 基本能判断瓶颈在存储。iostat专门看磁盘。iostat -x 1输出很关键重点看%util和await。%util 接近 100% 只代表设备忙但 SSD 和机械盘的 100% 含义完全不同还要结合awaitIO 平均等待毫秒数和r_svc/w_svc判断。如果%util不高但await很高通常是磁盘队列堆积或者硬件性能差。我见过不少案例表面是“数据库慢”实际是云盘底层带宽被打满%util看着不高await却几百毫秒。sar是历史数据的救命工具。装了 sysstat 后系统会定时采样保存出问题时直接sar -uCPU、sar -r内存、sar -bIO、sar -n DEV网络回看当时状态。没有监控系统的小规模环境sar 基本就是唯一的“时光机”。2.2 第二梯队pidstat、perf、strace 与上下文切换排查第一梯队定位到维度后第二梯队负责把问题钉到进程甚至函数。pidstat -u -p PID 1持续观察某个进程的 CPU 使用率pidstat -w -p PID 1可以看进程的上下文切换次数。上下文切换高通常意味着线程太多、锁竞争激烈或者频繁系统调用这是“CPU sy 高”最常见的幕后黑手。perf top用于看内核和用户态的热点函数。比如 CPU 高但不知道是哪段代码在烧perf top可以直接显示占用率最高的函数名。配合perf record和perf report可以在压测时采样程序跑完后拿到类似火焰图的数据。很多“CPU 莫名其妙飙高”的问题最后都是用perf在几秒钟内找到元凶的。strace -p PID -c统计进程的系统调用适合定位“接口为什么慢”。比如发现stat、open系统调用特别多那很可能是代码里频繁读配置或反复检查文件存在属于典型的低效代码。需要注意strace在线附加进程会影响性能高峰期慎用。2.3 网络与磁盘专项ss、iotop 与丢包定位网络排查我用ss多于 netstat它更快、输出也更友好。ss -s看连接统计ss -lnt看监听端口ss -ti可以看到每条 TCP 连接的重传、RTT 等细节。如果 TIME_WAIT 堆积严重要考虑连接复用和端口范围问题这节后面细讲。磁盘方面iotop能按进程实时显示 IO 读写速率定位“谁在疯狂写盘”特别好用。很多服务器突然变慢最后查出是日志进程在刷屏或者某个备份任务在暴力读盘iotop一眼就能揪出来。3. 核心子系统调优从内核参数到存储与网络工具是用来定位的真正解决问题往往要落到系统配置和应用代码上。这一章讲各子系统的常用调优手段。先说一句大实话不是所有参数都值得改下面这些是我在多个环境实测过、确实有效的其他飘在网上的玄学参数要学会放弃。3.1 CPU 与进程调优绑定、优先级与中断分散CPU 维度常见的优化有三类进程绑定、优先级调整、中断分散。进程绑定用taskset。比如一台 16 核机器上跑了一个对延迟敏感的服务可以用taskset -c 0-3把它绑定到前 4 个核避免线程在不同核之间迁移带来的缓存失效和调度开销。注意不能让所有服务都绑核否则剩余核浪费严重反而拖累整体吞吐。优先级调整用nice和renice。让后台批处理任务以低优先级运行避免和线上业务抢 CPU。比如nice -n 10 ./backup.sh数值范围 -20 到 19越小优先级越高普通用户只能往低优先级调root 可以调高。数据库主从备份、日志压缩这类任务我都习惯配上 nice成本极低收益立竿见影。中断分散方面多队列网卡可以把每个队列的中断绑定到不同 CPU避免所有中断打在一个核上。简单做法是打开irqbalance服务让它自动均衡追求极致时再手动修改/proc/irq/.../smp_affinity。对大多数场景irqbalance已经够用手工调容易调错。我见过某个团队为了让网卡中断均衡手工绑核后把 NUMA 拓扑绑错了跨 NUMA 访问内存反而让性能更差。3.2 内存调优swap、HugePages 与 OOM 兜底内存优化的第一件事是理解free -h的输出。Linux 的 buff/cache 是拿来用文件缓存的内存应用内存不够时内核会自动回收所以看到 buff/cache 占用高不用恐慌。真正要警惕的是 swap 的 si/so 持续不为 0说明内存已经不够用了回收缓存也补不上缺口。vm.swappiness控制内核使用 swap 的倾向默认 60。对跑数据库或 Java 应用的机器一般建议调到 10 左右让内存优先给到应用但对某些内存本来就小的机器盲目调低反而更快 OOM。我踩过这个坑后来都是边压测边观察sar -B的 fault 数据再决定。修改方式sysctl -w vm.swappiness10 echo vm.swappiness10 /etc/sysctl.conf大页 HugePages 能减少 TLB miss适合数据库等频繁访问大块内存的场景。但对一般互联网应用我建议先关掉透明大页 THP因为 THP 在内存碎片化时容易触发卡顿。数据库机器上比较常见的做法是echo never /sys/kernel/mm/transparent_hugepage/enabled再用静态 HugePages 给数据库专用内存这个操作需要数据库配合别只改内核。OOM 兜底也很重要。给关键进程设置oom_score_adj让它被 OOM Killer 选中时排在后面同时打开vm.panic_on_oom0让系统先尝试回收而不是直接重启。生产环境里关键进程守护脚本是必备的但内核层的 oom_score_adj 往往更直接配合 systemd 的 Restart 策略能省不少事。3.3 文件系统与磁盘 IO 调优磁盘 IO 调优先看挂载参数。ext4/xfs 默认会记录访问时间 atime每次读文件都要更新元数据增加写放大。对大部分非审计类业务挂载时加noatime能白赚一点 IO 性能代价只是访问时间不更新几乎没人依赖它。改挂载参数前先看现有挂载方式mount | grep noatime如果没有noatime可以通过mount -o remount,noatime /data临时调整再写进/etc/fstab持久化。I/O 调度器方面传统机械盘建议用mq-deadline或bfqSSD/NVMe 建议用none等同 noop因为 SSD 没有寻道时间也不需要排队算法。查看当前调度器cat /sys/block/sda/queue/scheduler临时修改echo none /sys/block/sda/queue/scheduler永久修改要写到内核启动参数或 udev 规则里否则重启失效。数据库日志和业务数据放不同磁盘、日志文件不要和系统盘抢 IO这些属于架构层面的调优效果往往比调内核参数更大。另外日志轮转logrotate的触发时间尽量避开业务高峰否则一到整点所有实例同时切日志磁盘 IO 直接打满就是一次典型的“定时炸弹”。3.4 网络协议栈调优别再乱抄 sysctl网络相关的 sysctl 参数是重灾区。网上很多“高并发内核参数优化”帖子互相抄有的参数在新内核里已经废弃。我筛选了几个仍然有效、且实际有用的net.core.somaxconn 1024 net.ipv4.tcp_max_syn_backlog 1024 net.ipv4.ip_local_port_range 1024 65000 net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_fin_timeout 15 fs.file-max 1000000somaxconn和tcp_max_syn_backlog决定 accept 队列和半连接队列长度高并发 Web 服务默认值偏小排队连接容易被丢弃表现为“请求偶尔超时”ip_local_port_range扩大本地可用端口范围适合大量短连接出站的场景tcp_tw_reuse只对客户端生效允许复用 TIME_WAIT 连接配合tcp_fin_timeout调短可以缓解 TIME_WAIT 堆积。需要特别提醒网上流传的tcp_tw_recycle参数千万不要照抄。它在旧内核可以快速回收 TIME_WAIT但会带来 NAT 环境下连接错乱的问题而且新内核早就移除了这个参数写了也没用。网络性能优化还要关注网卡多队列和中断合并生产操作前一定要在测试环境验证。4. 实战案例Nginx PHP-FPM 服务从“慢得像乌龟”到 QPS 翻倍前面是散点知识这一节用一个真实得不能再真实的案例把它们串起来。某次我给一个客户做 Nginx PHP-FPM 的老业务优化现象是高峰期接口响应越来越慢QPS 上不去用户投诉变多。整个过程大概花了一个下午用了前面提到的工具和参数。4.1 现象描述与初步定性现象是CPU 总体使用率不高us 只有 20% 左右但 load average 长期超过 CPU 核数wa 一直徘徊在 40% 以上。业务侧表现为接口平均耗时从 120ms 涨到 800msp99 更是到了 3 秒。初步判断是 IO 瓶颈而不是 CPU 或内存瓶颈优先查磁盘。4.2 用工具一步步定位瓶颈先抓vmstat 1 10果然 IO 等待列 wa 居高不下运行队列 b 也持续大于 0再用iostat -x 1定位到是哪块盘发现根分区%util接近 100%await200ms 以上明显是机械盘被打满了。用iotop揪出罪魁祸首两个进程在疯狂写盘。一个是 PHP-FPM 的 slow log另一个是 Nginx 的 access log日志量巨大恰好日志文件又和业务数据放在同一块盘上。内存充足应用本身没有代码级性能问题问题核心就是日志 IO 干扰了正常读写。4.3 优化动作落地方案针对这个根因做了一组组合拳日志分离把 Nginx access log、PHP-FPM slow log 分别指向独立挂载的磁盘应用日志和数据盘物理隔离降低日志量access log 关闭或改为按天采样保留真实日志离线分析slow log 的阈值从 1 秒改为 3 秒只记录真正慢的请求启用 Nginx 的 open_file_cache 和日志缓冲减少每次写日志的系统调用顺手调整内核网络参数提升somaxconn、tcp_fin_timeoutPHP-FPM 的pm.max_children根据内存实际测算后从 64 调到 128内存充足单进程占 30MB 左右没有超卖风险加了一层 Redis 缓存把原来每次都要查 MySQL 的热点数据缓存起来减少数据库磁盘读。Nginx 配置关键片段worker_processes auto; worker_rlimit_nofile 65535; http { open_file_cache max10000 inactive60s; open_file_cache_valid 80s; access_log /data/logs/nginx/access.log combined buffer32k flush5s; gzip on; gzip_min_length 1k; }PHP-FPM 配置关键片段pm dynamic pm.max_children 128 pm.start_servers 32 pm.min_spare_servers 16 pm.max_spare_servers 64 slowlog /data/logs/php-fpm/slow.log request_slowlog_timeout 3s4.4 优化效果与复盘优化后同样的压测场景下QPS 从 1800 提升到 4200接口 p99 从 3 秒降到 400ms磁盘%util降到 30% 左右。其实没动什么“高深”参数就是先把无谓的 IO 抢占用去掉再让日志和数据分离。复盘时最深刻的体会是性能优化很多时候不是“加更快的硬件”而是“停止做没意义的事”。5. 常见问题速查与面试高频题实录最后这部分把日常巡检和面试中最常遇到的 Linux 性能问题整理成速查表同时聊聊我踩过的坑。无论你是要做技术分享还是准备面试都值得收藏。5.1 经典故障对照表现象、定位、解法现象可能原因常用排查命令建议操作load average 很高CPU 却空闲进程处于 D 状态等待 IOtop 看 D 状态进程vmstat b 列iostat -x查对应盘的 IO 和存储健康状态CPU us 高sy 不高应用计算密集pidstat -u 定位进程perf top 看热点代码级优化、加机器、降负载CPU sy 高us 不高上下文切换频繁或系统调用过多vmstat 的 cs 列pidstat -wstrace -c减少线程数、减少锁竞争、批量系统调用内存明明还有却开始 swap内核优先回收文件缓存或 swappiness 偏高free -hsar -Bvmstat si/so按业务调低 vm.swappiness排查内存泄漏接口偶发超时TCP 握手慢accept 队列满、半连接队列丢包netstat -s 看 SYN 丢弃ss -lnt调大 somaxconn、tcp_max_syn_backlog检查应用 accept 速率磁盘 %util 不高但延迟高队列等待、文件系统碎片或硬件降级iostat 的 await、svctmsmartctl换硬件、调整调度器、检查 RAID 卡策略5.2 面试与晋升答辩里绕不开的 Linux 性能问题我把这些年面试候选人时必问的几个 Linux 性能问题整理出来自己也经常在团队分享中讲请你解释 load average 的含义为什么 load average 高不一定代表 CPU 饱和CPU 使用率 100% 时你会怎么一步一步排查什么情况下你会调整 vm.swappiness调整的依据是什么上下文切换过高怎么定位怎么降低进程 OOM 了系统会怎么选进程如何保护关键进程文件描述符被耗尽怎么排查ulimit 和 fs.file-max 的区别是什么这些问题没有标准答案但回答时只要抓住“先定位再优化用数据说话”这个主线基本不会跑偏。比如 CPU 100% 的问题正规回答是先top确认是用户态还是内核态再用pidstat定位进程用perf定位函数最后回到代码层面分析是死循环、正则回溯还是锁竞争而不是上来就说“重启一下”。5.3 关于“性能优化”的三个误区与我的实操经验最后说几个我栽过的跟头。第一个误区是“参数改得越多越有成就感”。实际上大部分线上问题改 2 到 3 个参数就能解决改得越多越难回滚和排障。第二个误区是“照搬网上的优化脚本”。不同硬件、不同内核、不同业务模型参数差异很大网上脚本很容易把 SSD 当成机械盘调或者把虚拟化环境调崩溃。第三个误区是“优化完不验证”。改完配置要用压测或真实流量对比基线确认 p99、吞吐、错误率都符合预期才算完否则只是自我安慰。我个人现在做性能优化的流程已经固定先收集监控和日志再压测建立基线然后用 vmstat、iostat、pidstat、perf 做定位改最少的配置最后压测验证并留下一份变更记录。这套流程不一定花哨但能保证大多数场景不出大错。最近我正在整理容器环境下的 CPU 绑核和内存回收案例还有一个火焰图分析专题的原始数据等跑完压测拿到对比结果后会继续更新到这个系列里。
返回列表