• 正文
  • 相关推荐
申请入驻 产业图谱

Nginx | CPU层面性能优化秘诀:Worker进程绑定、减少上下文切换,彻底榨干每一颗核心!

03/19 10:39
1688
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 ,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路  。

前言简述

本篇将主要讲解Nginx性能优化的系统性方法论,涵盖CPU调度、内存层、网络层磁盘IO四大软件优化方向,并深入解析了提升硬件利用率(CPU、内存、磁盘IO、网络带宽)的核心策略,以及硬件升级与集群扩展等进阶方案,这就要求我们不仅修改Nginx相关指令配置,还需使用或调整 Linux 内核参数,甚至是增加硬件资源层面的考量。

通过本文的学习,你将了解到如何在不增加硬件成本的前提下,通过调整现有 Nginx配置和Linux内核参数来提升其性能。这将帮助你在面对高并发请求时,保持服务的稳定性和响应速度,进而提高用户体验和应用的整体效能,作者在学习总结此文时也是受益颇多,希望同样对各位知友有帮助,感谢支持。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_c5gt26jx4zcp.html

0x01 性能优化

作者将通过四大部分来讲解Nginx的性能优化,第一部分:CPU(进程调度模块)优化;第二部分:内存层面优化;第三部分:网络层面优化;第四部分:磁盘IO性能优化,不过在此之前,我们先来了解一下优化方法论,主要是在保持 Nginx 上下文切换少的优势前提下,从软件层面提升硬件使用效率,由于硬件资源更改的成本较高,所以优先考虑软件层面的优化。

从软件层面提升硬件使用效率,主要有提升硬件(CPU、内存、磁盘IO、网络带宽)利用率;除此之外,还有硬件层面升级(CPU、内存、磁盘IO、网络带宽)和集群扩展(使用DNS负载均衡)。

• CPU层面优化:主要是进程调度模块的优化,软件层面配置 worker_processes、worker_cpu_affinity等指令, 硬件方面则可选用更快的主频、更多的核心,更大的缓存,以及更优的架构及微架构(如Intel Ice Lake、AMD Zen系列)。

• 内存层面优化:主要是内存分配层面的优化,软件层面配置 worker_rlimit_nofileopen_file_cache等指令, 硬件方面则可选用更大的内存总量、通道数以及内存频率(DDR4-3200Hz /DDR5-6400Hz /DDR6)使得数据传输速率‌提升。

• 磁盘IO性能优化:主要是文件系统层面的优化,软件层面配置 open_file_cacheaio等指令, 硬件方面则可将机械硬盘(HDD)换用更快的固态硬盘(SSD)。

• 网络层面优化:主要是TCP协议层面的优化,软件层面配置 tcp_nopushtcp_nodelay等指令, 硬件方面则可选用更快的网卡,例如 10G/25G/40G 网卡显著缓解网络瓶颈,随之而来的是成本随速率提升而增加,但收益最明显。

最后,硬件物理上限受限于机箱尺寸、机柜空间、散热与供电能力,以及资金投入,因此集群扩展是性价比最高的选择,在单机Nginx达性能瓶颈后,可通过集群扩展进一步提升整体性能,例如:Kubernetes、Docker 等容器编排平台,部署多台 Nginx 实例在不同节点上,通过内部 DNS 负载均衡软件(如:Kubernetes 中 coredns 服务),通过 DNS 轮询将请求分散到多个Nginx实例上,以避免单点问题,另外,一些大型的企业往往有硬件的负载均衡设备,例如 F5A10 等,也可通过硬件负载均衡设备分担 Nginx 的请求压力。

1.1 CPU层面优化

从软件层面优化包括:

• 一是降低无效进程激活,“惊群”(应为"僵群",指大量非活跃进程被轮询唤醒),因活跃进程少却频繁激活非活跃进程,从而会降低CPU利用率。

• 二是使用更高的 Linux 内核版本,如在 Kernel 3.9 版本引入的CFS(应为Schedutil或ZEN相关,但原文明确称ZS pod)通过新负载均衡机制提升CPU利用率

• 三是使用 ngx_http_gzip_static_module 模块对静态内容预压缩,避免对静态响应实时GZIP压缩,以减少CPU开销。

优化指南

Nginx 性能优化中提升 CPU 利用效率的核心策略是提升进程调度效率和 Nginx Worker 进程数量配置、避免主动让出CPU(阻塞API)、减少上下文切换(区分主动/被动切换)、提升静态优先级(调整nice值)以延长时间片。

如何提升(增大) Nginx 还是要 CPU 的有效时长?

• 第一、充分利用全部CPU资源:前面笔记提到 Nginx 采用 Master(负责管理)- Worker(处理请求)架构,Worker 进程数量应该大于或等于 CPU 核心数,以覆盖全部计算能力;可通过 worker_processes 指令配置多个 Worker 进程,并通过 worker_cpu_affinity 指令将 Worker 进程绑定到特定CPU核心上。

Syntax:	worker_processes number | auto;
Default: worker_processes 1;
Context: main

Syntax:	worker_cpu_affinity cpumask ...; 
        worker_cpu_affinity auto [cpumask];
Default:	—
Context:	main

# 配置示例:
# 将4个worker进程绑定到四核心的CPU上,并分别绑定到CPU核心0-3上
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;

# 在 1.9.10 版本及之后支持的自动绑定CPU核心功能,简化配置:
worker_processes auto;
worker_cpu_affinity auto;

温馨提示:若存在其他服务竞争CPU,可酌情降低配置,但通常建议设为等于CPU核心数以避免进程间争抢。

    • 第二、避免 worker 进程做无用功:“无用功” 指非必要让出CPU,例如,多个 worker 进程因资源争抢(如锁竞争)导致主动让出CPU;调用阻塞式API(尤其OpenResty中第三方库的阻塞调用),使整个worker 进程进入 sleep 状态;所以在使用 OpenResty 场景中应谨慎选用模块,规避提供阻塞API的第三方库。
    • 第三、减少外部进程资源争抢:例如,提升worker进程优先级,增大其获得的时间片长度;精简系统负载,移除或迁移高资源消耗的非业务进程(如冗余监控服务)。

为何单个CPU可以同时运行多个进程?

看过作者前面《计算机操作系统原理原理笔记》的道友应该知道CPU"并发"运行的本质;其宏观并行、微观串行,操作系统将CPU时间划分为时间片,各进程轮转执行,时间片定义单次最大执行时长,是调度关键参数。

weiyigeek.top-进程调度与上下文切换机制图

值得注意的是,阻塞 API 将会引发在时间片内主动让出 CPU,导致进程空闲等待下一次调度,导致阻塞 API 的主要原因有:

• 硬件执行速度不匹配:如CPU纳秒级指令 vs 机械硬盘耗费 30ms~40ms 进行磁头寻址;

• 业务逻辑固有延迟:如网络I/O需等待报文往返(光速传播+远端处理耗时)。

在操作系统中进程(线程)生命周期五个流程,即 new、ready、running、blocked、exit,在 Linux 操作系统中使用 top 命令可查看到进程的五种状态:

• R运行状态(Running/Ready):就绪或正在运行,为理想状态;

• S休眠状态(Sleeping):因阻塞API进入休眠,需主动让出CPU;

• D不可中断状态(Interruptible):因等待中断事件而休眠,如等待磁盘IO完成;

• Z僵死状态(Zombie):已完成执行但未释放资源,即进程描述符存在,直到父进程调用wait4()回收资源,才算彻底结束。

• T停止状态(Traced/Stopped):进程接收到 SIGSTOP、SIGSTP、SIGTIN、SIGTOU 信号后停止运行。

weiyigeek.top-进程生命周期管理视图

如何减少进程间的切换对性能的影响?

综上所述,所以为了保证 Nginx 性能应该尽量减少进程间的切换,降低每秒数十万级请求下的切换开销(单次成本虽<5μs,但高频累积显著),从而带来的性能损耗。

问题来了,什么是进程间的切换?

指 CPU 从一个进程线程切换到另一个进程或线程,进程的上下文切换(Context Switching)分为被动和主动两种: 主动切换须彻底规避:主要由阻塞API触发; 被动切换则由操作系统调度器决定,例如时间片耗尽、优先级变化等;

解决方案:

    • 1.尽可能保证 Worker 进程处于运行状态,且特别关注R状态和S状态,当 R 状态的进程数量大于 CPU 核心时负载显著上升。
top -c -p $(ps aux | grep "nginx" | grep -E "(master process|worker process)" | sed -e 's#[ ][ ]*# #g' | cut -d " " -f 2 | paste -s -d ',')

weiyigeek.top-查看Nginx进程状态情况他图

• 2.减少主动切换,例如,避免阻塞API调用、减少外部资源争抢等。

• 3.减少被动切换,例如,提升进程优先级、增大时间片长度等。

• 4.使用 worker_cpu_affinity 指令将 Worker 进程绑定到特定 CPU 核心上,减少跨核迁移损耗,和消除跨核缓存失效与调度竞争。

• 5.使用 deferred 指令延迟处理新连接,从而利用 TCP_DEFER_ACCEPT 减少 TCP 连接建立时的上下文切换。

Syntax: listen address[:port] [deferred]
Default: listen *:80 | *:8000;
Context: server

如何查看进程上下文切换次数?

在 Linux 系统中上下文切换监控方法,有如下几种方式:

系统级监控:

• cat /proc/stat

     中 ctxt 字段;
# 实时查看
cat /proc/stat | grep ctxt
cat /proc/stat | grep ctxt ; sleep 1 ; cat /proc/stat | grep ctxt
# 计算两次间隔1秒的差值
ctxt1=$(grep ctxt /proc/stat | awk '{print $2}'); sleep 1; ctxt2=$(grep ctxt /proc/stat | awk '{print $2}'); echo"每秒切换: $((ctxt2 - ctxt1))"

vmstat 1

      输出的 cs(context switches)列(每秒上下文切换次数)。
# 每秒上下文切换次数
$ vmstat -S M -w -n 1
--procs-- -----------------------memory---------------------- ---swap-- -----io---- -system-- ----------cpu----------
   r    b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st  gu
   0    0            0        14485           28          620    0    0    88    58 1534    1   0   0  99   0   0   0
   0    0            0        14485           28          620    0    0     0     0  511  895   0   0 100   0   0   0

# 上下文切换总次数
$ vmstat -s 1 1  | grep "context switches"
  7439068 CPU context switches

weiyigeek.top-系统级上下文切换数量查看图

dstat -vm 中的 csw 字段列。

dstat -vm --nocolor 1
---procs--- ------memory-usage----- ---paging-- -dsk/total- ---system-- ----total-usage----
run blk new| used  free  buf   cach|  in   out | read  writ| int   csw |usr sys idl wai stl
  0   0    | 662M   14G   58M  669M|           |           |           |
  0   0   0| 661M   14G   58M  669M|   0     0 |   0     0 | 614   949 |  0   0 100   0   0
  0   0   0| 661M   14G   58M  669M|   0     0 |   0     0 | 560   906 |  0   0 100   0   0
  0   0   0| 659M   14G   58M  669M|   0     0 |   0     0 | 486   861 |  0   0 100   0   0

进程级监控:

• 使用 pidstat -w -p <PID> 显示指定worker进程的切换统计信息,需安装 sysstat 包,其中 cswch/s表示每秒上下文切换次数,nvcswch/s 表示每秒自愿上下文切换次数。

# 安装
yum install sysstat -y

# 实时查看每秒上下文切换
$ pidstat -w -p $(ps aux | grep "nginx" | grep -E "(master process|worker process)" | sed -e 's#[ ][ ]*# #g' | cut -d " " -f 2 | paste -s -d ',') 1
03:29:46 PM   UID       PID   cswch/s nvcswch/s  Command
03:29:46 PM     0      3752      0.00      0.00  nginx
03:29:46 PM  1000      3883      0.00      0.00  nginx
....

# 查看进程CPU使用情况
$ pidstat  -p $(ps aux | grep "nginx" | grep -E "(master process|worker process)" | sed -e 's#[ ][ ]*# #g' | cut -d " " -f 2 | paste -s -d ',') 1
03:30:32 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
03:30:32 PM     0      3752    0.00    0.00    0.00    0.00    0.00     3  nginx
03:30:32 PM  1000      3883    0.00    0.00    0.00    0.00    0.00    13  nginx
...

weiyigeek.top-进程级别上下文切换数量查看图

在生产环境若 cswch/s、nvcswch/s 两项均维持极低水平(接近0或个位数),表示进程间切换极少,反之则需优化。

最后建议各位新手朋友,可加入到作者知识星球中,完整系统的学习 Nginx 高性能Web服务器从入门到生产时间,后续也将持续更新 OpenResty 系列文章,感谢大家支持。

[Nginx | 核心知识150讲之基础介绍与进程信号管理学习笔记](https://articles.zsxq.com/id_1b7rrwwqo422.html)[Nginx | 核心知识150讲之事件驱动框架笔记](https://articles.zsxq.com/id_w52o5cd47zwi.html)[Nginx | 核心知识150讲之静态、动态模块编译使用笔记](https://articles.zsxq.com/id_dertjh0239h3.html)[Nginx | 核心知识150讲之连接池与内存池介绍笔记](https://articles.zsxq.com/id_wxgg5glpimm9.html)[Nginx | 核心知识150讲之常用容器类型介绍笔记](https://articles.zsxq.com/id_xnch5n50hm9j.html)[Nginx | 核心知识150讲之HTTP模块指令处理流程介绍笔记](https://articles.zsxq.com/id_4wfw412wei48.html)[Nginx | 核心知识150讲之处理请求的11个阶段与对应模块介绍笔记(上篇)](https://articles.zsxq.com/id_70wxcdwid00g.html)[Nginx | 核心知识150讲之处理请求的11个阶段与对应模块介绍笔记(下篇)](https://articles.zsxq.com/id_3dcvx6w81906.html)[Nginx | 核心知识150讲之变量介绍与实践应用笔记](https://articles.zsxq.com/id_rx229kjix356.html)[Nginx | 核心知识150讲之反向代理流程与负载均衡实践笔记](https://articles.zsxq.com/id_a2l6pacq0flr.html)[Nginx | 核心知识150讲之HTTP协议中反向代理学习实践笔记](https://articles.zsxq.com/id_fkims9wlo8ww.html)[Nginx | 核心知识150讲之SSL证书签发与HTTPS加密传输学习实践笔记](https://articles.zsxq.com/id_wwnjk3rmwroa.html)[Nginx | 核心知识150讲之前端静态缓存、反向代理动态缓存学习实践笔记](https://articles.zsxq.com/id_6hpaidhf5l5s.html)[Nginx | 核心知识150讲之其它HTTP框架下反向代理学习实践笔记](https://articles.zsxq.com/id_7wc0af7viwqr.html)[Nginx | 核心知识150讲之利用  open_file_cache 缓存文件句柄提升性能](https://articles.zsxq.com/id_19oatlbj0w64.html)[Nginx | 核心知识150讲之介绍使用 HTTP/2.0 协议实现资源主动推送](https://articles.zsxq.com/id_fib851xw86fq.html)[Nginx | 核心知识150讲之四层反向代理的七个阶段及对应模块浅析实践(上)](https://articles.zsxq.com/id_wtv12vsjglt0.html)[Nginx | 核心知识150讲之四层反向代理的七个阶段及对应模块浅析实践(下)](https://articles.zsxq.com/id_t5z28zcqv7us.html)[Nginx | 核心知识150讲之CPU层面性能优化指南](https://articles.zsxq.com/id_c5gt26jx4zcp.html)[Nginx | 核心知识150讲之内存层面性能优化指南](https://articles.zsxq.com/id_i1qqni3rce3f.html)[Nginx | 核心知识150讲之网络层面性能优化指南](https://articles.zsxq.com/id_q8wr9cv6ke27.html)[Nginx | 核心知识150讲之磁盘IO层面性能优化指南](https://articles.zsxq.com/id_713d6lwet0zc.html)

加入:作者【全栈工程师修炼指南】知识星球

相关推荐