目录

Nginx性能优化与实战上

【Nginx】性能优化与实战(上)

本文详细介绍了Nginx的KeepAlive、反向代理、Gzip压缩等核心功能的配置要点。KeepAlive部分讲解了连接复用、超时设置及请求数限制;反向代理部分解析了连接超时、缓冲机制及Header设置;Gzip压缩部分说明了压缩类型选择、压缩级别及缓存控制。最后提供了前端部署案例和SSI技术的应用场景分析。文章重点阐述了各项配置的原理、使用场景及参数调优建议,帮助开发者根据实际需求进行合理的Nginx性能优化。

一、KeepAlive

1.使用场景
  • 可预知的连续操作:比如加载页面HTML后马上去请求JS和CSS资源等
  • 减少连接开销:通过复用连接,降低服务器的CPU和网络延迟
2.客户端使用

keepalive_timeout timeout [header_timeout];

  • 作用:设置一个KeepAlive连接在被服务器关闭之前,最长的空闲等待时间。
  • timeout:指定了空闲超时时间,默认为75秒。如果设置为0,则表示禁用KeepAlive。
  • header_timeout(可选):在响应头Keep-Alive: timeout=time中设置一个值,这个值可以被某些浏览器识别和使用。
  • 示例keepalive_timeout 65 65; 表示服务器空闲65秒后关闭连接,并通知浏览器连接的超时时间也是65秒。

keepalive_requests number;

  • 作用:定义了单个KeepAlive连接上可以处理的最大请求数量。当请求数达到这个阈值后,连接将被关闭。
  • 默认值:1000。

keepalive_time time;

  • 作用:设置一个KeepAlive连接总的存活时长。无论连接是否活跃,只要从建立开始超过了这个时间,就会被强制关闭。这是一个较新的指令(Nginx 1.19.10+)。
  • 示例keepalive_time 1h;

send_timeout time;

  • 作用:设置向客户端发送响应的超时时间。这个超时不是指整个响应的传输时间,而是指两次连续的Nginx向Browser写数据操作之间的最大间隔时间。
  • 重要陷阱:如果Nginx后面连接的应用有一个耗时很长的同步操作(例如超过60秒),在操作完成前Nginx没有向客户端发送任何数据,那么这个连接可能会因为send_timeout而被Nginx断开,导致用户收到错误。

https://i-blog.csdnimg.cn/direct/1eb580fa32804f8cb8a180dc651a54f2.png

3.上游服务器使用

在server或者location中:

proxy_http_version 1.1;

  • 作用:必须将代理请求的HTTP协议版本设置为1.1。因为HTTP/1.1默认支持KeepAlive,而HTTP/1.0需要显式声明Connection: keep-alive头。

proxy_set_header Connection "";

  • 作用:清除从客户端请求中继承来的Connection头。如果客户端的请求头是Connection: close,这个头默认会传递给后端服务器,导致后端用完就关闭连接。将其设置为空字符串,可以避免这种情况,从而让Nginx来管理与后端的连接状态。

在upstream中:

keepalive connections;

  • 作用:核心指令。定义了每个worker进程缓存的到上游服务器的最大空闲连接数。当有新的请求需要代理时,Nginx会优先从这些空闲连接中选取一个来使用,而不是新建连接。这个值不宜过大,但也不能太小,需要根据并发量和后端服务器的处理能力来设定。
  • 总连接数:系统总的空闲长连接数是 keepalive 的值乘以 worker_processes 的数量。例如,worker_processes 4;keepalive 128; 意味着Nginx最多会保持 4 * 128 = 512 个到后端的空闲连接。你需要确保后端服务器(Tomcat等)的最大连接数设置能够承受这个数量。

https://i-blog.csdnimg.cn/direct/92d1b27c757e463ba28c0f1163e2f9b7.png

https://i-blog.csdnimg.cn/direct/f5a62bb83c0d4569b4e2becf8e06d0c8.png

二、反向代理

1.连接与超时指令

这些指令控制Nginx和上游服务器之间连接的生命周期和容错能力

proxy_connect_timeout

  • 作用:定义Nginx与上游服务器建立TCP连接的超时时间。
  • 为什么要设置:这是实现“快速失败”(Fast-Fail)机制的关键。如果某个后端服务已经宕机或网络不通,Nginx不必长时间等待,而可以在这个设定的时间内快速判断连接失败,然后根据策略(例如proxy_next_upstream)尝试连接下一个后端服务。这可以有效防止请求在无效的后端服务上积压,提升系统的可用性。
  • 好比:打电话时,拨号后等待对方“接听”的最长时间。如果一直没人接,你就会挂断。

proxy_send_timeout

  • 作用:定义Nginx向后端服务发送请求数据时,两次连续写入操作之间的超时时间。请注意,它不是发送整个请求的总耗时。
  • 为什么要设置:用于防止与一个“假死”的后端服务建立连接后,在发送数据时卡住。比如,后端服务的接收缓冲区满了,无法再接收新的数据,此时Nginx的发送操作就会阻塞,这个指令可以防止无限期阻塞。
  • 好比:你给朋友发一个大文件,发送过程中,如果对方的网络突然卡住,导致你的发送进度条长时间不动,这个指令就会触发超时,中断发送。

proxy_read_timeout

  • 作用:定义Nginx从后端服务读取响应数据时,两次连续读取操作之间的超时时间。
  • 为什么要设置:这是最常用也是最重要的超时设置之一。它用于防止后端服务处理请求时间过长。如果后端因为复杂的业务逻辑、慢SQL或者死循环而长时间没有返回任何数据,Nginx会在等待超过这个时间后主动断开连接,并向客户端返回504 Gateway Time-out错误。这可以避免客户端请求被无限期挂起。
  • 好比:你问朋友一个问题,等待他回答的最长时间。如果他一直沉默不语,超过了你的耐心限度,你就会不等了直接走开(返回504)。

https://i-blog.csdnimg.cn/direct/00f70ead929e4fc3bef7b4b42890ea63.png

2.代理缓冲指令

proxy_request_buffering

  • 作用:决定是否启用客户端请求体的缓冲。

  • 工作模式

    • on (默认):Nginx会完整接收客户端发送过来的全部请求体(比如POST的JSON数据、上传的文件),将其存放在内存或临时文件中,然后再一次性地将完整请求发送给后端服务。
    • off:Nginx会边接收客户端的数据,边向上游服务器转发,实现“流式”传输。
  • 为什么要这样设计:默认开启缓冲,可以大大减轻后端服务的压力。后端服务可以一次性收到一个完整的、干净的HTTP请求,处理完后立即释放连接,而不必去适应客户端可能很慢的网络速度。只有在上传超大文件等特定场景下,为了避免Nginx磁盘I/O成为瓶颈,才会考虑关闭它。

proxy_buffering

  • 作用:这是总开关,决定是否启用对上游服务器响应的缓冲。

  • 工作模式

    • on (默认):Nginx会尽可能完整地接收后端服务返回的所有响应数据,存放在自己的缓冲区(内存或临时文件)中,然后再开始向客户端发送。
    • off:Nginx会边接收后端的数据,边同步地转发给客户端。
  • 为什么要这样设计:同样是为了解耦和保护后端。Nginx可以迅速接收完后端的数据,让后端服务“功成身退”,去处理其他请求。然后Nginx再根据客户端的网速慢慢地将数据发送给客户端,整个过程后端服务无需参与。这极大地提高了后端服务的吞吐能力。

当proxy_buffering on;时,以下指令共同定义缓冲区的行为:

proxy_buffer_size

  • 作用:设置用于存储上游响应第一部分(主要是HTTP响应头)的缓冲区大小。这块缓冲区通常不需要很大,但必须足够大以容纳所有的响应头。

proxy_buffers

  • 作用:设置用于存储上游响应**主体(body)**的缓冲区。它由缓冲区数量和每个缓冲区的大小两部分组成。例如,proxy_buffers 32 128k; 表示Nginx会为每个连接分配32个128KB的内存块用于缓冲响应体,总大小为 32 * 128KB = 4MB

proxy_max_temp_file_size

  • 作用:定义了这个临时文件的最大尺寸。如果响应数据连这个临时文件都装不下,Nginx会放弃缓冲,直接同步转发后续数据(如果可能),或者报错。

proxy_temp_path

  • 作用:指定用于存放这些临时文件的目录路径。levels参数可以创建分级子目录,避免单个目录下文件过多影响性能。

proxy_temp_file_write_size

  • 作用:设置Nginx在向临时文件写入数据时,每次写入的数据块大小。
3.Header设置指令

proxy_set_header

  • 作用:允许你修改或添加从Nginx发往上游服务器的请求头。
  • 为什么要设置:后端服务默认只能看到请求是来自Nginx的IP地址。为了让后端应用能获取到真实的客户端信息(如IP、域名、协议等),必须通过这个指令手动将这些信息添加到转发的请求头中。
  • 最常见的配置:

proxy_set_header Host $host; # 传递原始请求的域名
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 追加代理IP链
proxy_set_header X-Forwarded-Proto $scheme; # 传递原始请求的协议 (http/https)

https://i-blog.csdnimg.cn/direct/1100b75b17e74954ab74905a065fb033.png

三、Gzip

1.指令解析

gzip on|off;

  • 作用:Gzip功能的总开关。默认是关闭的(off)。
  • 用法:要使用Gzip,必须首先设置为on

gzip_types <mime_type> ...;

  • 作用:指定需要进行Gzip压缩的文件MIME类型。默认只压缩text/html
  • 为什么要设置:这是Gzip配置中最关键的一步。我们应该只对文本类文件进行压缩。像图片(JPG/PNG)、视频、PDF以及二进制文件通常不应该被Gzip,因为它们本身已经是高度压缩的格式,再次压缩不仅浪费CPU资源,有时甚至可能让文件体积变得更大。
  • 示例gzip_types text/plain application/javascript text/css application/json text/xml;

gzip_comp_level <level>;

  • 作用:设置Gzip的压缩等级,范围是1到9。
  • 权衡:数字越大,压缩比越高(文件被压缩得更小),但消耗的CPU资源也越多。数字越小,压缩比越低,但处理速度更快。通常,设置为4-6是一个比较理想的平衡点,可以在可接受的CPU开销下获得不错的压缩效果。

gzip_min_length <length>;

  • 作用:设置允许压缩的页面的最小字节数。只有当响应体的Content-Length大于这个值时,Nginx才会对其进行压缩。
  • 为什么要设置:对于非常小的文件,Gzip压缩本身带来的开销(CPU计算、添加HTTP头等)可能会超过其节省的带宽。设置一个合理的阈值(如256字节或1k)可以避免对小文件进行无效压缩。

gzip_proxied <off|any|...>;

  • 作用:当Nginx作为反向代理服务器时,根据后端服务器返回的响应头来决定是否对响应进行压缩。

  • 场景:比如后端服务可能已经对某些内容进行了压缩,或者通过Cache-Control头指定了不希望被代理缓存或修改。这个指令让Nginx可以更智能地处理这些来自上游的响应。

  • 常用值

    • off: 不对代理响应进行压缩。
    • any: 无条件对所有代理响应进行压缩。
    • auth: 当响应头中包含Authorization时才压缩。
    • expired, no-cache, no-store, private: 当响应头中包含相应的ExpiresCache-Control指令时,启用压缩。

gzip_vary on|off;

  • 作用:在响应头中添加Vary: Accept-Encoding
  • 为什么要设置:这个头非常重要。它告诉中间的代理缓存服务器(如CDN、公司的缓存代理),对于同一个URL,需要根据客户端的Accept-Encoding头来缓存不同的版本(一个压缩版,一个未压缩版)。如果没有这个头,缓存服务器可能会错误地把一个压缩版本返回给一个不支持Gzip的旧版浏览器,导致页面乱码。

gzip_buffers <number size>;

  • 作用:设置用于存储Gzip压缩结果的缓冲区数量和大小。例如gzip_buffers 16 8k;表示使用16个8KB的内存块。

gzip_http_version <1.0|1.1>;

  • 作用:启用Gzip所需的最低HTTP协议版本。默认是1.1,通常保持这个设置即可。

gzip_disable "MSIE [1-6]\.";

  • 作用:通过正则表达式匹配客户端的User-Agent,对特定的浏览器禁用Gzip功能。
  • 为什么要设置:这是一个历史遗留选项,主要用于兼容一些古老的、对Gzip支持有问题的浏览器(如IE6)。

https://i-blog.csdnimg.cn/direct/6e090e23004f4db7b596bc5ba1166099.png

四、案例部署

1.前端文件存放

https://i-blog.csdnimg.cn/direct/ac5bee9b6c4d4d50baac61830dc47ef2.png

2.修改配置文件

在nginx.conf主配置文件添加模块化语句

https://i-blog.csdnimg.cn/direct/0149ab10a32743299bf91f79c5d1e68b.png

vim /usr/local/nginx/conf/conf.d/nginx_demo.conf

在nginx_demo.conf里面填写下面的配置代码


server {
    # 1. 监听端口
    listen 80;

    # 2. 绑定的域名,可以是IP地址或 localhost
    server_name hutao; # 或者填写您服务器的 IP 地址

    # 3. 前端项目静态文件根目录
    root /usr/local/nginx/html/dist;

    # 4. 默认首页文件
    index index.html index.htm;

    # 5. 前端路由与静态资源处理
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 6. 后端 API 接口反向代理
    location /api/ {
        # 代理的目标地址
        # 当 proxy_pass 的地址带有 URI 路径时 (例如末尾有 /): Nginx 会将 location 匹配的路径部分剔除,然后将剩余部分拼接到 proxy_pass 的地址上。
        # 当 proxy_pass 的地址不带 URI 路径时 (例如末尾没有 /): Nginx 会将 location 匹配的完整路径直接拼接到 proxy_pass 的地址上
        proxy_pass http://127.0.0.1:8090;

        # 7. 设置请求头
        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_set_header X-Forwarded-Proto $scheme;

        # 8. (可选) 增加超时时间
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 9. (可选) 错误页面配置
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/nginx/html; # Nginx默认错误页面的存放路径
    }
}
3./的注意事项

https://i-blog.csdnimg.cn/direct/8c90bc525ee343efb37b67e0d06cd5d0.png

https://i-blog.csdnimg.cn/direct/03f20bffe0814aaf9f620dae6c86b521.png

五、SSI

1.基本介绍

理解为就是将多个HTML文件拼接到一起,变成一个逻辑上的HTML页面。如何不是对性能追求极致,个人认为用不上它,但是如果请求数量比较多的时候还是有用的。

https://i-blog.csdnimg.cn/direct/ff51990f0f544607bf8940566b6e0bdd.png

https://i-blog.csdnimg.cn/direct/87571b8e93a7424baa7710891a70a8c5.png

2.总结
  • 如果您在做一个纯粹的、内部使用的、不需要被搜索引擎收录的应用,或者是一个现代的单页面应用(SPA),那么使用 JavaScript 动态加载组件是完全正确且高效的。
  • 但如果您在做一个面向公众的、内容型的、SEO 和用户体验至关重要的网站,那么使用 Nginx SSI 这种服务器端拼接技术,确保一次性给到客户端完整内容,就绝不是多此一举,而是保证项目成功的基石。

六、文件同步

如果使用SSI技术同时nginx多集群部署后,有可能会存在文件不一致情况,故需要设置文件同步策略。

yum install -y rsync

vim /etc/rsyncd.conf

/etc/rsyncd.conf

全局配置

uid = root
gid = root
use chroot = no
max connections = 10
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid

定义一个名为 ‘www’ 的同步模块

[www]
path = /www/      # 数据实际存放的路径
read only = no    # 设置为 no,允许客户端写入数据
auth users = sgg  # 授权访问的用户名,可以自定义
secrets file = /etc/rsyncd.passwd # 存放用户名和密码的文件

格式: username:password

echo “sgg:111” > /etc/rsyncd.passwd

chmod 600 /etc/rsyncd.passwd

rsync –daemon

echo “111” > /etc/rsyncd.passwd.client
chmod 600 /etc/rsyncd.passwd.client

rsync -avz –delete –password-file=/etc/rsyncd.passwd.client /usr/local/nginx/html/ ::www

yum install -y automake

wget

tar -xvf inotify-tools-3.14.tar.gz

cd inotify-tools-3.14

./configure –prefix=/usr/local/inotify

make && make install

#!/bin/bash

MONITOR_DIR="/usr/local/nginx/html/"
TARGET_HOST=“192.168.44.105”
TARGET_MODULE=“www”
RSYNC_USER=“sgg”
CLIENT_PASSWD_FILE="/etc/rsyncd.passwd.client"

/usr/local/inotify/bin/inotifywait -mrq –timefmt ‘%Y-%m-%d %H:%M:%S’ –format ‘%T %w%f %e’ \
-e close_write,modify,delete,create,attrib,move ${MONITOR_DIR} | while read file
do
    # 这里的 -az 等同于 -avz,但省略了 -v
    rsync -az –delete –password-file=${CLIENT_PASSWD_FILE} ${MONITOR_DIR} ${RSYNC_USER}@${TARGET_HOST}::${TARGET_MODULE}
    echo “${file} was synced to ${TARGET_HOST} at $(date)” » /var/log/rsync_realtime.log
done

chmod +x realtime_sync.sh
nohup ./realtime_sync.sh &  # 使用nohup让它在后台持续运行