
前两天帮一位朋友处理了一台跑了好几年的 CentOS 7 服务器业务不算重但响应越来越慢。我上去之后没有急着找网上的优化脚本而是先花了小半小时把系统当前的状态摸了一遍结果在 /etc/sysctl.conf 里发现了一堆来路不明的参数其中赫然写着net.ipv4.tcp_tw_recycle 1。看到这里我心里大概有数了这台机器的“卡”很可能就是当年被某篇“性能调优”文章坑出来的。这就是我写这篇东西的原因。CentOS 7 的系统优化与性能调优网上资料多如牛毛但大部分是“抄完参数就完事”从不解释为什么也不管你的业务到底是什么场景。这篇文章我就把自己在实际运维里的一套完整做法梳理出来从新装系统后的基础检查、yum 源排错、内核参数调整到磁盘 I/O、业务场景和虚拟机环境的特殊情况一层一层讲清楚。无论你是刚用 Minimal ISO 装完系统不知道下一步干什么还是手上有一台“未优化”的服务器想系统性地处理一遍这篇文章应该都能给出一份可以直接照做的路线图。1. 新装 CentOS 7 别急着调先把家底摸清楚普通人拿到一台 CentOS 7 之后最容易犯的错就是一上来就打开系统优化教程照着 sysctl.conf 改一通。但这其实非常危险因为你连瓶颈在哪都不知道改出来的参数大概率是在帮倒忙。我坚持的原则是先评估后改动再验证。这一步能省掉后面无数个“怎么改完反而更慢了”的深夜。1.1 Minimal 安装带来的省内存假象很多人用的是 CentOS-7-x86_64-Minimal-2009.iso 这个镜像Minimal 版本确实干净装完什么都不做内存占用可能就 150M 到 250M 左右看起来比桌面版“优化”多了。但这只是假象因为 Minimal 为了追求体积把一堆运维必需的诊断工具都砍掉了。你top可能都不一定装得顺手更别说iostat、sar、pidstat这些性能分析神器。等你发现系统卡了才去yum install sysstat这时候已经浪费了宝贵的排障时间。我自己的习惯是新装完 CentOS 7 之后第一件事不是调优而是先补齐诊断工具yum -y install net-tools sysstat htop lsof tcpdump bind-utils systemctl start sysstat systemctl enable sysstat这里sysstat特别重要它安装后会通过 cron 定时采样系统的 CPU、内存、磁盘、网络等指标数据存在 /var/log/sa/ 下面。等过几天业务出了问题你能拿出之前的历史数据来看趋势而不是靠猜。这一套逻辑和“未开启系统优化怎么解决”这类问题的核心诉求其实一样先把系统的真实状态暴露出来才有资格谈优化。1.2 让 lscpu、free、vmstat 先说话摸家底靠的就是几条最基础的命令但要真正看懂输出而不是扫一眼就走。lscpu看 CPU 架构是 x86_64 还是 aarch64核数、频率、超线程状态。这个命令在 ARM 机器上输出和 x86 有一些差异别误判。free -h看内存总量、已用、swap 使用情况。重点看 swap 有没有被大量写入如果 swpd 一直很高说明物理内存已经吃紧后续调优方向就得往内存倾斜。df -hT看分区挂载情况以及文件系统类型。CentOS 7 默认根分区通常是 xfs如果你有数据盘确认一下挂载参数。vmstat 1 10这是我最常用的动态命令。重点关注si和so两列如果这两个值始终不为 0说明系统一直在 swap 换入换出内存瓶颈实锤了。另外wa列高说明 CPU 在等磁盘 I/O磁盘可能才是元凶。uname -a看内核版本后面选 I/O 调度器和部分 sysctl 参数时要用到。我一般会把这些输出存一份命名类似 /root/sysinfo_before_$(date %Y%m%d).txt。为什么要留档因为调优一周后老板问你“优化效果到底怎么样”你要是拿不出前后对比数据说再多也没说服力。1.3 调优前的基线数据必须留一份既然是“调优”就一定要有对比基线。没有基线你只能凭感觉说“好像快了”出了问题你也不知道是自己改坏的还是业务波动这是运维大忌。我通常会在改动前统一下记录这些内容# 内核参数快照 sysctl -a /root/sysctl_before.txt # 资源限制快照 ulimit -a /root/ulimit_before.txt # CPU/内存/IO 动态快照 vmstat 1 10 /root/vmstat_before.txt iostat -x 1 5 /root/iostat_before.txt # 当前挂载与分区 mount /root/mount_before.txt df -hT /root/df_before.txt这些命令非常简单但难得有人真正落地。调优不是一场说走就走的旅行你至少得知道自己从哪个车站出发的。2. yum 源报错排查repomd.xml 那个 errno -1 卡住多少人如果说系统评估是“摸家底”那么 yum 源就是 CentOS 7 的“补给线”。在 CentOS 7 上yum 源有问题你连诊断工具都装不全更别提调优了。很多朋友第一次接触这个系统第一只拦路虎就是下面这行报错http://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml: [Errno -1] 下载失败网上搜这个报错答案五花八门但十有八九都会让你重新下载 repo 文件。问题是很多人重下了好几遍还是报错。我来说说这个报错背后真正的机理。2.1 报错根因不是 yum 本身是网络路径repomd.xml是 yum 仓库的元数据入口每次执行 yum 都会先去拉取这个文件。Errno -1不是 HTTP 404它通常是 libcurl 层面的连接失败也就是说 yum 根本没拿到这个文件而不是文件不存在。按我排障的习惯遇到这个报错直接用 curl 去复现curl -v http://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml -o /dev/null看输出卡在哪一步。常见的坑按出现频率排网络根本不通服务器在隔离网段或者只开放了 80/443 之外的其他端口yum 默认用 http 访问如果防火墙只放行了业务端口这一步肯定挂。DNS 解析失败ping mirrors.aliyun.com不通或者能 ping 通 IP 但用域名不行。先nslookup mirrors.aliyun.com确认一下。系统时间偏差太大如果走的是 https 源证书校验会因为时间不对直接失败。CentOS 7 自带 chrony先看timedatectl再用chronyc makestep手动同步一下。yum 缓存坏了之前断网导致元数据写了一半yum clean all之后再yum makecache重来。repo 文件重复定义/etc/yum.repos.d/ 下面可能有多个 repo 文件都定义了同一个 base 仓库互相覆盖也会出现诡异错误。所以遇到 errno -1别急着重装系统先按这个链条排查大概率十分钟内能定位。2.2 换阿里源时最容易踩的坑国内换源阿里镜像是比较稳的选择。常规操作是先备份原 repo 文件再下载阿里的 repomv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo yum clean all yum makecache这个步骤本身没问题但我见过不少同事漏了一步下载完没有检查文件内容。下载下来的 repo 文件里变量$releasever和$basearch会自动展开成当前系统的版本号和架构。如果系统没有正确读取 os-release或者你把其他发行版的 repo 文件放进来展开结果就会错位。所以下载完一定要看一眼内容head -n 20 /etc/yum.repos.d/CentOS-Base.repo确认 baseurl 用的是centos/$releasever/os/$basearch/这种标准写法。还有个小坑如果这台机器之前配置过代理检查一下 /etc/yum.conf 里有没有proxy行有些遗留的代理配置会导致连接全往错误的地方走。2.3 aarch64 架构换源的隐藏路径差异现在 ARM 服务器越来越常见比如云上的 aarch64 实例、国产 ARM 服务器甚至树莓派 4B 都能装 CentOS 7。很多朋友直接把 x86_64 的 repo 文件复制过去只把$basearch改成 aarch64结果就是死活找不到源报 404 或者 errno -1。问题出在路径上。x86_64 的仓库在阿里镜像是centos/7/os/x86_64/但是 aarch64 的仓库不在centos/7/os/aarch64/而是在centos-altarch/7/os/aarch64/这个路径下。正确的 repo 写法是[base] nameCentOS-$releasever - Base baseurlhttp://mirrors.aliyun.com/centos-altarch/$releasever/os/$basearch/ gpgcheck1 gpgkeyhttp://mirrors.aliyun.com/centos-altarch/RPM-GPG-KEY-CentOS-7[updates] 和 [extras] 同理。这个“altarch”的坑非常隐蔽网上很多教程根本没提我当时也是在 ARM 机器上折腾了一个多小时才反应过来。如果你手里的机器是 aarch64 架构换源的时候一定要检查是不是走到了 altarch 目录。3. sysctl 内核参数只讲参数不讲原理等于埋雷前面铺垫了这么多终于到了很多人最感兴趣的环节内核参数调优。但我要先泼一盆冷水sysctl 里的参数几乎都是“牵一发而动全身”的你只抄数值不搞懂原理早晚出事。我先放一套我用了很多年、在绝大多数业务场景下都比较稳妥的基础配置然后再逐个说为什么。# /etc/sysctl.d/99-tuning.conf fs.file-max 2097152 fs.aio-max-nr 1048576 net.core.rmem_max 16777216 net.core.wmem_max 16777216 net.core.rmem_default 262144 net.core.wmem_default 262144 net.core.somaxconn 4096 net.core.netdev_max_backlog 65536 net.ipv4.tcp_max_syn_backlog 65536 net.ipv4.tcp_syncookies 1 net.ipv4.tcp_fin_timeout 30 net.ipv4.tcp_keepalive_time 600 net.ipv4.tcp_keepalive_intvl 75 net.ipv4.tcp_keepalive_probes 9 net.ipv4.tcp_tw_reuse 1 net.ipv4.ip_local_port_range 1024 65535 vm.swappiness 10保存后执行sysctl --system让配置生效。3.1 建议先开的连接与队列参数net.core.somaxconn是 listen 队列的上限Nginx 这类服务在 listen 时也会指定自己的 backlog最终生效的是两者中较小的那个。默认值 128 对稍有点并发量的业务来说太小了所以调到 4096 是低风险的常见操作。net.ipv4.tcp_max_syn_backlog是半连接队列长度也就是服务器收到 SYN 但还没完成三次握手的连接数量上限。业务正在做高并发推广时如果这个值太小新连接会被直接丢弃表现就是用户访问超时但服务器负载看着不高。net.ipv4.tcp_syncookies 1是为了防 SYN Flood正常情况下它几乎不影响性能属于开了不亏的保险。net.ipv4.ip_local_port_range从默认的 32768 60999 扩大到 1024 65535是为了让服务器作为客户端主动发起大量短连接时本地端口没那么容易被耗尽。这里的典型场景是后端服务频繁调用 MySQL、Redis 或外部 API。这几个参数都只影响并发连接的上限不怎么改变协议兼容性所以我敢说它们比较安全。3.2 TCP TIME_WAIT 和 tcp_tw_recycle 的教训每次看到网上有人推荐net.ipv4.tcp_tw_recycle 1我都想说一句快删了吧兄弟。tcp_tw_recycle和tcp_tw_reuse经常被混在一起讨论但这俩完全不是一回事。tcp_tw_reuse是允许客户端复用处于 TIME_WAIT 状态的连接配合tcp_timestamps使用对出站连接有帮助开它问题不大。而tcp_tw_recycle是启用后对进入的 SYN 连接使用基于时间戳的“快速回收”机制。问题在于这个机制假设同一个源 IP 的所有连接时间戳是单调递增的。一旦你服务器前面挂了 NAT、负载均衡或者大量用户通过同一出口访问不同客户端的内核时间戳很可能不一致新连接就会被内核误判成“乱序的老包”直接丢掉。症状非常典型一部分用户完全打不开另一部分用户却一切正常重启服务后短暂恢复过一会儿又犯病。网上那些把tcp_tw_recycle当救命稻草的教程害了不知道多少台服务器。CentOS 7 默认tcp_tw_recycle 0请继续保持 0。TIME_WAIT 比较多的时候优先去调tcp_fin_timeout或者让业务层复用连接而不是开这种会破坏协议语义的参数。3.3 内存页缓存与 swappiness 怎么配vm.swappiness是大家最爱改的参数之一它控制内核倾向于把匿名页换到 swap 的程度范围 0 到 100CentOS 7 默认 60。数据库类业务通常希望尽可能把内存留给缓存所以把 swappiness 调低是合理的我一般设 10。但我不建议设成 0。很多人把 0 理解成“永远不用 swap”其实内核在极端内存压力下仍然可能换页而且设置了 0 之后内存不够时会更容易触发 OOM Killer把业务进程直接杀掉。对生产环境来说留一点 swap 做缓冲比直接 OOM 要好尤其是物理内存只有 4G 以下的小机器。另外两个参数容易被人忽略vm.dirty_ratio和vm.dirty_background_ratio。这俩控制脏页回写的节奏。默认 background_ratio 是 10dirty_ratio 是 20。如果磁盘比较慢而应用写比较多一次触发到 dirty_ratio 会造成很明显的写入卡顿。对高并发写入场景我会保守地调低一点vm.dirty_background_ratio 5 vm.dirty_ratio 10但如果你跑的是大内存服务器且磁盘性能很好过低的 dirty_ratio 反而会导致 page cache 利用不足写性能下降。这又是一个“没有万能参数”的例子必须结合自己的业务。3.4 连接追踪、端口范围和最常被忽视的 sem用 iptables 的 state 或 related 规则时内核会启用 nf_conntrack 连接追踪。如果你服务器并发连接数大经常会遇到这种报错nf_conntrack: table full, dropping packet解决办法是把net.netfilter.nf_conntrack_max调大。但在调之前你需要知道一个代价每个 conntrack 条目大约要消耗 350 字节左右的内存。我按经验给个参考nf_conntrack_max预估内存消耗65536默认约 23 MB262144约 92 MB1048576约 350 MB所以不是调得越大越好100 万条差不多就吃 350M 内存了内存小的机器要谨慎。另外要注意如果内核没有加载 nf_conntrack 模块直接写这个参数会报错。先modprobe nf_conntrack_ipv4加载再写入配置。再说一个被严重忽视的参数kernel.sem。这是 System V 信号量的四个配置值很多数据库和消息中间件重度依赖信号量。默认值250 32000 100 128在高并发进程场景下很容易撞顶表现为程序报“semget 失败”或者“No space left on device”但磁盘明明是满的。遇到这种问题我会保守地调成kernel.sem 250 512000 100 2048然后用ipcs -l确认当前值和系统使用情况。4. 资源限制与调度ulimit、systemd 和 tuned内核参数调整完接下来是用户态资源限制。很多朋友只改 sysctl结果连接数还是上不去因为根本没意识到操作系统还有 ulimit 这一层限制。4.1 ulimit 的完整生效链路文件描述符限制是最常被卡住的地方。把这个绕明白才算真正的系统优化入门。CentOS 7 里常见的有三层内核层fs.file-max系统全局能打开的文件描述符总数。PAM 层 /etc/security/limits.conf针对用户的资源限制。systemd 服务层通过 service 单元文件里的LimitNOFILE指定。默认情况下普通用户 nofile 限制通常是 1024对跑高并发业务的服务来说完全不够。我一般会在 limits.conf 里加上* soft nofile 65535 * hard nofile 65535 * soft nproc 65535 * hard nproc 65535但注意CentOS 7 还有一个隐藏坑/etc/security/limits.d/20-nproc.conf 里默认写了* soft nproc 4096会覆盖 limits.conf 里的 nproc 设置。很多人改了 limits.conf 发现进程数还是上不去就是被这个文件卡了。需要的话直接改 20-nproc.conf或者把上面那几行也写进这个文件里。改完别急着高兴新开的 SSH 会话才会加载新 limit。如果服务是 systemd 拉起的还要检查对应单元的配置。4.2 systemd 服务的 Limit 参数这是一个折磨过无数人的细节你在 /etc/security/limits.conf 里把 nofile 改成 65535然后重启了 Nginx结果进程还是只能开 1024 个文件描述符。为什么因为 systemd 管理的服务不读 limits.conf它只认 unit 文件里的 LimitNOFILE 等字段。我现在遇到 Nginx、MySQL 这类服务都会先看一眼它的 systemd unitsystemctl cat nginx然后在 [Service] 段里加[Service] LimitNOFILE65535 LimitNPROC65536改完执行systemctl daemon-reload systemctl restart nginx想确认生效没有可以用这两条命令的任一个systemctl show nginx -p LimitNOFILE cat /proc/$(pgrep -f nginx: master)/limits看进程的实际 limits 是最直接的任何配置文件写得天花乱坠最后还是以/proc/pid/limits为准。4.3 tuned 到底值不值得用CentOS 7 自带的 tuned 很多人不知道或者知道了也懒得用。它的作用是把一堆“性能调优配置”按场景打包通过 tuned-adm 一键切换。我自己的态度是能用它当基础但要清楚它在干什么。例如想追求吞吐量可以直接yum -y install tuned tuned-adm profile throughput-performance tuned-adm activethroughput-performance这个 profile 会调整部分 sysctl 参数、磁盘调度策略甚至 CPU 的能耗管理比手动一个个改省事。但这里有个大坑tuned 的 profile 会覆盖你手动写在 /etc/sysctl.conf 里的某些设置而且两者同时存在时顺序未必如你所愿。如果你已经手动维护了一套 sysctl 配置就别既开 tuned 又手动改二选一。我个人的经验是云主机和虚拟机直接用 tuned 的virtual-guest或throughput-performance做基线物理机上想要更细微的控制再关闭 tuned 手动调。5. 磁盘与文件系统响应慢的问题一半在这里很多业务“变慢”不是 CPU 也不是内存而是磁盘 I/O 在拖后腿。CentOS 7 默认的 I/O 调度、挂载参数和文件系统选择对很多场景来说都只是“能用”离“好用”还有距离。5.1 从 lsblk 和 iostat 看磁盘真相调整磁盘之前先把现状看清楚。lsblk看磁盘和分区的拓扑关系确认是整块盘还是 LVM、RAID。cat /sys/block/sda/queue/rotational返回 1 是机械盘0 是 SSD。这决定了你后面选 I/O 调度器的方向。iostat -x 1 5看 %util、await、aqu-sz。这里我要提醒一个新手常犯的错iostat里的%util在 SSD 上经常显示 100%但它并不完全等于“磁盘真的在满负荷跑”。NVMe 这类盘的并行能力很强单队列指标参考意义有限。所以别一看 %util 高就急着给磁盘扩容先看看aqu-sz平均队列长度和await平均响应时间。如果await只有几毫秒说明响应很快只是应用持续在写这个“虚高”要能分清楚。5.2 挂载参数选择noatime、barrier、discard文件系统挂载参数是性价比极高的优化点。查看当前挂载参数findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS大部分场景我第一件事就是加noatime,nodiratime。默认情况下每次读文件都会更新 atime 时间戳这会产生额外的写 I/O。对大多数业务来说atime 根本没卵用关掉之后可以明显减少无意义的写入。改 /etc/fstab 里对应行例如/dev/mapper/vg-data /data xfs defaults,noatime,nodiratime 0 0然后重新挂载生效。还有一个讨论度很高的参数SSD 要不要开discard挂载选项discard会在文件删除时向 SSD 发 TRIM 命令理论上能维持长期写入性能但实际使用中频繁 TRIM 反而可能引发一些 SSD 的写放大。我更推荐的做法是别在挂载参数里开 discard而是用 cron 定期执行fstrim -av比如每周一次0 3 * * 1 /sbin/fstrim -av这样既保证 SSD 空间得到回收又不会让每笔 IO 都背 TRIM 的负担。至于barrier0这种为了极限性能关闭日志屏障的做法我强烈不建议在生产环境用。它省下来的性能很少但一旦断电文件系统损坏的概率会明显上升你确定要用一块盘的数据安全赌那点吞吐吗5.3 I/O 调度器在现代内核里怎么选CentOS 7 默认内核是 3.10I/O 调度器只有那么几个noop、deadline、cfq。新的 mq-deadline、kyber、bfq 是更新内核才有的事情所以别在网上直接复制新内核教程回来会找不到文件。查看当前调度器cat /sys/block/sda/queue/scheduler简单选择原则虚拟机里跑 CentOS 7用noop。因为宿主机已经做了一层 I/O 调度虚拟机内部再排队没意义反而增加延迟。物理机上的机械硬盘用deadline它兼顾了读写请求的公平性和延迟。物理机上的 SSDdeadline或noop都行实际性能差别非常小别太纠结。临时修改echo deadline /sys/block/sda/queue/scheduler永久生效建议用 udev 规则不要每次开机手动改。创建一个 /etc/udev/rules.d/60-io-scheduler.rules# 机械盘用 deadline KERNELsd*, ATTR{queue/rotational}1, ATTR{queue/scheduler}deadline # SSD 用 noop KERNELsd*, ATTR{queue/rotational}0, ATTR{queue/scheduler}noop如果你用的是 virtio 磁盘设备名是 vd* 而不是 sd*规则里要额外加上vd*。我自己踩过的坑就是这个写了半天规则结果磁盘是 /dev/vda规则根本没匹配上。6. 业务场景验证调优MySQL 和 Web 服务的实战系统层调优最终要落在业务上。很多人把 sysctl 改了一堆然后业务一跑还是慢原因就是把系统调优和业务调优割裂开了。这里我挑两个最常碰到的场景展开说。6.1 MySQL 在 CentOS 7 上最有效的几个参数CentOS 7 默认仓库里的是 MariaDB 5.5版本偏老很多新特性没有。跑轻量业务没问题但如果你对并发和数据一致性有要求建议先换 MySQL 官方仓库或者升级 MariaDB 10.x否则下面的参数也有一部分用不上。拿到一台专门跑数据库的 CentOS 7 服务器我先看 /etc/my.cnf 里的这几个点[mysqld] max_connections 500 max_connect_errors 10000 innodb_buffer_pool_size 4G innodb_log_file_size 256M innodb_flush_log_at_trx_commit 2 slow_query_log 1 slow_query_log_file /var/log/mysql-slow.log long_query_time 1innodb_buffer_pool_size是 MySQL 的命脉默认 128M 对任何正经业务来说都不够。怎么算我的经验是如果这台机器只跑 MySQL比如物理内存 8G先减掉系统和其他进程预留的 2G剩下的 6G 里再取 60% 到 70%也就是 4G 左右比较合适。如果上面还放着 Nginx、Redis 等别的服务buffer pool 要再降一些。innodb_flush_log_at_trx_commit这个参数值得说道说道。它有三个值1 是每次事务提交都刷盘最安全性能最差2 是每秒刷一次盘性能好但断电可能丢一秒以内的事务0 是交给操作系统性能最好也最不安全。金融交易类必须用 1一般互联网业务我非常推荐 2性能和安全的平衡点比较好。用 0 的属于心太大。query_cache_type 0是我强烈建议的。MySQL 的查询缓存听起来很美但在高并发写入场景下它要频繁失效和重建反而成了全局锁一样的东西。新版 MySQL 已经把这个特性废除了老版本上直接关掉省心。慢查询日志一定要开这是你判断后续优化方向最重要的数据来源。6.2 Nginx 这类网络服务与内核参数如何配合Nginx 在 CentOS 7 上跑得好不好一来靠应用配置二来靠内核参数配合。一个非常容易被忽略的关联是Nginx 的 listen backlog 和内核net.core.somaxconn必须联动。如果你在 nginx.conf 里只写成server { listen 80; }那么实际 backlog 取内核的 somaxconn。如果内核我调到 4096Nginx 这里可以显式声明同样大的值server { listen 80 backlog4096; }判断 backlog 是否够用不需要猜直接看ss -lnt输出里的 Recv-Q 列。如果 80 端口的 Recv-Q 长期接近 4096说明 accept 不过来连接在排队需要继续调大作业。这个观察方法我用了很多年比看一大堆监控曲线都直接。我自己常用的 Nginx 基础配置长这样worker_processes auto; events { worker_connections 65535; use epoll; } http { keepalive_timeout 60; server_tokens off; }worker_connections 65535要和前面的 ulimit 配套否则文件描述符不够用Nginx 会直接报错“too many open files”。worker_processes auto会自动按 CPU 核数分配 worker大多数场景都是最省心的玩法。6.3 调优后如何用数据证明有效调优最怕的是“自我感觉良好”。我每次改完配置都会用同一套压测命令跑一遍记录前后数值。例如用 ab 简单压测 Web 服务ab -n 20000 -c 200 http://127.0.0.1/test重点看 Requests per second、Time per request 和 Failed requests。调优前后用同样参数各压一次数据说话比什么都强。同时开一个 vmstat 在旁边看着记录压测过程中的上下文切换次数cs 列。这里有个反直觉的点有时候你增加 worker 进程吞吐没上去cs 反而暴涨说明大量 CPU 时间都浪费在进程切换上了。这时候把 worker 数量降回去往往性能更好。调优不是堆参数而是找平衡点。MySQL 类的调优验证也类似开慢日志看执行时间、看SHOW GLOBAL STATUS里的 Threads_connected、QPS 变化。无论什么系统核心方法都是一样的一次只动一个变量记录前后差异再决定下一步。7. 虚拟机环境注意事项VirtualBox、VMware 和 aarch64最后聊一个很多人实际在用的场景CentOS 7 装在虚拟机上。网上很多优化教程默认你有一台物理机但在 VirtualBox、VMware 里一套操作下来可能不但没优化反而把虚拟机搞得更卡。7.1 虚拟机上哪些优化可以省掉在 VirtualBox 上新建 CentOS 7 虚拟机我一般给 2 核 CPU、2G 到 4G 内存磁盘用 VDI 动态扩展类型网络按需选 NAT 或桥接。这些属于安装阶段的基础配置和“性能调优”关系不大但会影响后续体验。虚拟机里第一个该省掉的优化就是折腾 CPU 频率和电源管理。Guest 系统里看到的cpufreq调节基本都是虚的真正控制频率的是宿主机你在虚拟机里折腾半天效果微乎其微。第二个是 I/O 调度器。虚拟机内的磁盘本质上是一块模拟设备I/O 已经经过宿主机一层调度你再去选 cfq、deadline 反而多一层排队。我在 5.3 里说过了虚拟机建议直接用 noop 这种最简调度器。第三个要省掉的是没必要去关一堆看起来没用的 systemd 服务。Minimal 安装的服务已经很少了那些节流方案省下的内存还不够你多开一个 Java 进程塞牙缝反倒可能误关依赖导致网络出问题。把时间花在真正的瓶颈上别做无效努力。7.2 VMware Tools 和 VirtualBox 增强功能装不装虚拟机里装增强工具不是“可选项”我建议都装。不装的话网络驱动可能停留在比较低效的模拟模式剪贴板共享、拖拽文件这些便利功能也没有鼠标切换还有延迟。VMware 环境里CentOS 7 大概率可以直接用 open-vm-toolsyum -y install open-vm-tools systemctl enable vmtoolsd如果仓库里没有再走官方 VMware Tools 的 ISO 安装路径但记得提前装好 kernel-devel 和 gcc否则编译内核模块会失败。VirtualBox 用的是 Guest Additions也就是“增强功能”。挂载增强功能 ISO 后执行yum -y install kernel-devel gcc make perl mount /dev/cdrom /mnt /mnt/VBoxLinuxAdditions.run装完后重启共享文件夹、无缝鼠标、动态分辨率就都能用了。很多朋友反馈 VirtualBox 里 CentOS 7 鼠标飘、屏幕分辨率调不高基本都是没装增强功能导致的。7.3 虚拟化下最容易踩的整数倍陷阱最后提醒一个常见的虚拟机性能误区不要给虚拟机分配超过宿主机物理内存的额度也不要分配太多 vCPU。给一台双核宿主机分配 8 个 vCPU 到虚拟机上CPU 争抢带来的上下文切换开销比多核带来的性能收益大得多。我见过有人给 VirtualBox 虚拟机配了 16G 内存宿主机才 8G结果宿主机会不停 swap整个系统拖垮。另外如果是在 ARM 虚拟化环境或者云上 aarch64 实例里跑 CentOS 7换源问题我在第 2 章已经详细说过路径要用centos-altarch这一点一定要记住。磁盘和网卡尽量选 virtio 半虚拟化设备性能比模拟的 SATA 和 e1000 好很多这是在虚拟化环境里真正有明显感知的优化。我调了这么多年 Linux 系统最大的体会就是系统优化与性能调优的本质不是把网上看到的参数全部抄一遍而是先弄清楚瓶颈到底在哪里再有针对性地去改。曾经有一台服务器大家都说“系统卡”我上去一看swap 一直在高频读写可内存明明还有很多最后发现就是 swappiness 设得过高一条参数改下来立刻见效。另一台机器各种内核参数调了一个遍也没起色最后才查出来是磁盘控制器驱动不对跟 sysctl 一点关系都没有。这些案例教会我同一个道理动手之前多问几个为什么比盲目执行一百条优化命令重要得多。如果你手上正有一台 CentOS 7 需要整理先把这套流程走完你大概率不会再走回头路。