欢迎光临
我们一直在努力

Nginx 三件套实战:源码编译、零停机平滑升级与性能调优(附完整配置与信号时序)

Nginx 三件套实战:源码编译、零停机平滑升级与性能调优(附完整配置与信号时序)

环境基线:Rocky Linux 10 + Nginx 1.26.x(文中所有命令实测可用,请按你的发行版调整) 标签:Nginx / 性能调优 / Linux / 运维 / 反向代理

目录

  • 一、为什么非要源码编译
  • 二、编译安装:从 configure 到 systemd
  • 三、平滑升级:零停机换版本(信号时序)
  • 四、性能调优:从进程模型到内核参数
  • 五、常见问题 QA(实战踩坑合集)
  • 六、结语

一、为什么非要源码编译

线上 Nginx 还是老版本?想加一个 lua 或 echo 模块,却发现发行版仓库版装不了第三方模块?大版本升级又不敢停业务?这篇把三个问题一次解决。

先回答第一个:为什么放弃 dnf install nginx 而选源码编译。

维度软件源安装(rpm/dnf)源码编译
第三方模块 ❌ 无法挂载(需静态编译进核心) ✅ –add-module 自由扩展
版本选择 跟随发行版仓库(通常滞后) 任意官方 release
编译参数 固定 可定制路径、日志、PID、模块
升级控制 依赖仓库 完全自主(配合平滑升级)
维护成本 高(需自行管理依赖与更新)

结论:追求稳定省心用软件源;需要模块扩展或深度定制,选源码编译。本文按「编译安装 → 平滑升级 → 性能调优」三段展开,每段都能直接落地。

二、编译安装:从 configure 到 systemd

2.1 环境准备

# 编译依赖:gcc/make + PCRE2(正则)/zlib(gzip)/openssl(TLS)
dnf install -y gcc make pcre2-devel zlib-devel openssl-devel git tar

# 创建运行用户(worker 进程最小权限运行)
id nginx &>/dev/null || useradd -r -s /sbin/nologin nginx

⚠️ 依赖务必一次装齐:缺 pcre2-devel 会在编译时报错,缺 openssl-devel 无法启用 SSL 模块——而这类错误要到 make 阶段才暴露。

2.2 configure:参数即架构决策

cd /usr/local/src/nginx-1.26.2
./configure \\
–prefix=/usr/local/nginx \\ # 安装基准目录
–sbin-path=/usr/sbin/nginx \\ # 可执行文件路径
–conf-path=/etc/nginx/nginx.conf \\ # 主配置路径
–error-log-path=/var/log/nginx/error.log \\
–http-log-path=/var/log/nginx/access.log \\
–pid-path=/var/run/nginx.pid \\ # PID 文件(systemd 依赖)
–lock-path=/var/run/nginx.lock \\
–user=nginx –group=nginx \\ # worker 进程身份
–with-http_ssl_module \\ # HTTPS
–with-http_v2_module \\ # HTTP/2
–with-http_realip_module \\ # 反代场景真实客户端 IP
–with-http_stub_status_module \\ # /status 监控指标
–with-http_gzip_static_module \\ # 预压缩静态资源
–add-module=/usr/local/src/echo-nginx-module # 第三方模块静态编译

关键认知:configure 是一次性"架构决策"——路径、模块清单在编译期定死,后期改路径要重新编译。参数务必进 Git/Ansible,保证可复现。

2.3 编译、安装与 systemd 托管

make -j$(nproc) && make install

tee /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t # 语法门禁:配置错则不启动
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable –now nginx

nginx -V # 确认 configure arguments
ss -tlnp | grep ':80' # 确认监听

systemd unit 三个要点:

  • Type=forking + PIDFile:告诉 systemd 跟踪哪个 PID,否则 start 后误报失败;
  • ExecStartPre=/usr/sbin/nginx -t:语法错误被拦在启动之前;
  • ExecStop=/bin/kill -s QUIT:优雅退出(排空存量连接)。
  • ⚠️ 版本号核实:网上不少教程出现 nginx-1.30.4 等非官方版本号(官方当前主线 1.27.x、稳定版 1.26.x)。生产请以 nginx.org 下载页 为准,警惕非官方 fork 与捆绑后门。

    三、平滑升级:零停机换版本(信号时序)

    3.1 为什么需要平滑升级

    • 直接 systemctl restart 会中断存量 TCP 连接;
    • 大版本升级有风险,需要可回滚;
    • Nginx 原生信号机制支持新旧 Master 短暂并存、逐批切换——这就是"平滑"的根基。

    3.2 信号速查表

    信号作用场景
    HUP 重载配置(平滑 reload) 改配置后生效,不停机
    USR1 重新打开日志文件 日志轮转
    USR2 启动新 Master(新旧并存) 升级新版本二进制
    WINCH 旧 Master 优雅关闭 worker 升级后排空旧连接
    QUIT 优雅退出(排空后退出) 关闭服务 / 升级收尾
    TERM/INT 快速退出 紧急停止

    3.3 升级五步法(附信号时序)

    # Step 1: 备份旧二进制 —— 用 mv 不用 cp!
    mv /usr/sbin/nginx /usr/sbin/nginx.old

    # Step 2: 编译新版本(configure 参数保持一致),覆盖安装
    cd /usr/local/src/nginx-1.27.4
    ./configure [与旧版完全相同的参数]
    make -j$(nproc)
    cp objs/nginx /usr/sbin/nginx

    # Step 3: USR2 —— 旧 Master 拉起新 Master(新旧并存)
    kill -USR2 $(cat /var/run/nginx.pid)

    # Step 4: WINCH —— 旧 Master 关闭全部旧 worker(存量连接排空)
    kill -WINCH $(cat /var/run/nginx.pid.oldbin)

    # Step 5: 确认稳定后 QUIT —— 退出旧 Master
    kill -QUIT $(cat /var/run/nginx.pid.oldbin)

    时序示意:

    旧 Master ──USR2──▶ 新 Master 启动(新旧并存,同监听 80/443)
    旧 worker ──WINCH─▶ 排空存量连接后优雅退出
    新 worker 持续处理新连接
    旧 Master ──QUIT──▶ 全部退出,升级完成

    3.4 回滚方案

    # 新版本有问题:用旧二进制接管
    kill -HUP /usr/sbin/nginx.old
    kill -QUIT $(cat /var/run/nginx.pid) # 退出新 Master

    3.5 两个高频坑

  • mv 而非 cp 备份旧二进制:cp 覆盖正在运行的可执行文件,USR2 升级时旧进程句柄指向被替换文件,可能直接崩溃;mv 保留旧文件可随时回滚;
  • 新旧 Master 并存期端口谁监听:新旧 Master 都监听 80/443,由内核 socket 队列分发连接,新老 worker 各自处理——升级全程无需维护窗口。
  • 参考:Nginx 官方控制文档(Signals)

    四、性能调优:从进程模型到内核参数

    原则:先测后调、单变量验证、以业务指标为准。以下为通用起点值,请用压测数据验证调整。

    4.1 进程与连接模型(瓶颈核心)

    # 全局块
    worker_processes auto; # auto = CPU 核数;IO 密集可 1.5~2×核数
    worker_rlimit_nofile 65535; # worker 可打开文件数上限(与 ulimit 联动)

    # events 块
    events {
    worker_connections 4096; # 单 worker 最大并发连接
    multi_accept on; # 一次 accept 多个新连接
    use epoll; # Linux 默认 epoll
    }

    并发估算:最大并发 ≈ worker_processes × worker_connections。注意 worker_connections 包含客户端 + upstream + FastCGI 所有连接,纯反代场景实际可用客户端数要打折。

    为什么 epoll 是根基(对比三种 IO 模型):

    • BIO(Apache prefork):一连接一线程,并发=线程数,内存爆炸;
    • select/poll:O(n) 遍历全部 fd,万级连接时每次唤醒扫 1 万次;
    • epoll:O(1) 事件驱动,内核只通知活跃连接——这就是 Nginx 高并发的秘密。

    4.2 传输与 IO 调优

    http {
    sendfile on; # 零拷贝:内核直接发文件
    tcp_nopush on; # 配合 sendfile 攒满包再发(大文件吞吐)
    tcp_nodelay on; # 禁 Nagle(小包低延迟)
    keepalive_timeout 65; # 客户端长连接保持时间
    client_max_body_size 64m; # 上传限制(按业务调)
    }

    4.3 压缩与缓存

    gzip on;
    gzip_vary on;
    gzip_comp_level 4; # 4~6 为性价比区间,越高 CPU 越贵
    gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;

    # 静态资源强缓存(文件名带 hash 时可用 immutable)
    location ~* \\.(jpg|jpeg|png|gif|css|js|svg|woff2?)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off; # 静态资源不记日志,减 IO
    }

    4.4 反代场景(upstream)调优

    upstream backend {
    ip_hash; # 会话有状态(验证码等)保持粘性
    server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
    keepalive 32; # 复用与后端空闲连接,减少握手
    }

    location /api/ {
    proxy_pass http://backend;
    proxy_http_version 1.1; # upstream keepalive 必需 HTTP/1.1
    proxy_set_header Connection ""; # 清空 Connection 头才能复用
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_connect_timeout 5s; # 快速失败,防连接堆积
    proxy_read_timeout 30s;
    }

    4.5 内核参数(进阶,务必压测验证)

    # /etc/sysctl.d/99-nginx.conf
    net.core.somaxconn = 65535 # listen 队列上限
    net.ipv4.tcp_max_syn_backlog = 65535
    net.ipv4.ip_local_port_range = 1024 65535 # 反代出站端口池(高并发反代必须)
    net.ipv4.tcp_tw_reuse = 1 # 快速复用 TIME_WAIT 端口
    sysctl -p /etc/sysctl.d/99-nginx.conf

    ⚠️ 内核参数影响全局,重启后才会生效,先在测试环境压测验证再上线;tcp_tw_reuse 仅适用出站连接(客户端/反代侧)。

    4.6 调优验证三板斧 + 实测对比

    # 1. 确认进程模型生效
    ps aux | grep 'nginx: worker' | grep -v grep | wc -l # 应 = worker_processes

    # 2. 压测(ab 单机快速验证)
    ab -n 100000 -c 1000 -k http://localhost/ | grep -E 'Requests per second|Failed requests|Non-2xx'

    # 3. 监控指标(启用 stub_status)
    # location /status { stub_status; }
    curl http://localhost/status

    调优前后对比(请填入你实测的数据):

    指标调优前调优后提升
    Requests per second (占位:实测填入) (占位:实测填入)
    Failed requests (占位) (占位)
    平均响应时间 (占位) (占位)

    指标解读:Reading/Writing 高说明未完成请求多(调 worker_connections 或查慢后端);Waiting 高是空闲 keepalive 多(正常)。

    五、常见问题 QA(实战踩坑合集)

    Q1:nginx -t 报 Permission denied? 非 root 执行导致:[emerg] open() "/var/run/nginx.pid" failed (13: Permission denied)。用 sudo nginx -t 校验;并把日志/pid 目录属主对齐:chown -R nginx:nginx /var/log/nginx。systemd unit 里 ExecStartPre 以 root 自动校验,可彻底规避。

    Q2:./configure 报 no …/config was found? 第三方模块源码未正确获取(目录缺失/下载不完整),configure 找不到模块的 config 描述符。重新 git clone –branch <tag> 稳定版(禁止 master),并 ls -la <module>/config 确认后再 configure。

    Q3:反代 502 / 验证码不显示? 502 = Nginx 无法把请求转发到后端。三板斧:ps aux | grep 后端进程 → ss -tlnp | grep 8080(是否监听)→ tail /var/log/nginx/error.log | grep upstream。EL9 别忘了 SELinux:getenforce 为 Enforcing 时 setsebool -P httpd_can_network_connect 1。

    Q4:为什么升级备份必须 mv 而不是 cp? 见 3.5 节:cp 覆盖运行中的二进制,USR2 升级时旧进程句柄指向被替换文件可能崩溃;mv 保留旧文件可用于回滚。

    Q5:worker_connections 设了 4096 为什么还扛不住? 该值包含客户端 + upstream + FastCGI 全部连接;且要确认 worker_rlimit_nofile 与系统 ulimit -n 联动调大,否则 fd 先耗尽。

    六、结语

    源码编译给你模块自由,平滑升级给你变更自由,性能调优给你容量自由——三者构成完整的 Nginx 生命周期管理能力。两条铁律收尾:

  • 可复现优先:configure 参数、unit 文件、内核参数全部纳入配置管理(Ansible/Terraform),杜绝服务器手改;
  • 数据说话:任何调优都用压测建立基线、单变量验证,别凭感觉。

  • 参考

    • Nginx 官方文档:https://nginx.org/en/docs/
    • Nginx 信号与控制:https://nginx.org/en/docs/control.html
    • echo-nginx-module(OpenResty 生态):https://github.com/openresty/echo-nginx-module
    • 压测工具:ApacheBench(ab)、wrk、hey

    本文首发于个人技术博客,欢迎转载注明出处。

    赞(0)
    未经允许不得转载:171主机测评 » Nginx 三件套实战:源码编译、零停机平滑升级与性能调优(附完整配置与信号时序)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址