Lazy loaded image
后端
Nginx从入门到精通:高性能负载均衡、反向代理与核心功能实战指南
字数 14266阅读时长 36 分钟
2024-4-28
2025-5-9
type
status
date
slug
summary
tags
category
icon
password

一、Nginx深入浅出:高性能HTTP反向代理服务器

Nginx (engine x) 是当今负载均衡技术领域的主流选择,几乎在所有规模的Web项目中都能看到它的身影。它是一款轻量级、高性能的HTTP反向代理服务器,同时也是一个通用的代理服务器,支持包括TCP、UDP、SMTP、HTTPS在内的绝大多数网络协议。
notion image
与我们之前讨论过的《Redis深度解析》类似,Nginx的核心架构基于I/O多路复用模型 (epoll/kqueue等)。这使得Nginx同样具备资源占用少、并发支持高的显著特点。理论上,单节点Nginx可同时处理高达5万并发连接,在实际生产环境中,配合良好的硬件基础和适当的系统调优,这一数值是完全可以达到的。
我们来看一下引入Nginx前后,客户端请求处理流程的对比:
notion image
在没有Nginx的架构中,客户端直接请求目标应用服务器,由应用服务器独立完成所有请求处理工作。引入Nginx之后,所有客户端请求首先到达Nginx,Nginx根据预设规则将请求反向代理 (Reverse Proxy) 到后端的某一台具体应用服务器进行处理。应用服务器处理完毕后,将响应返回给Nginx,最后由Nginx将最终结果回传给客户端。
了解了Nginx的基本概念后,接下来我们将快速搭建Nginx环境,并深入探讨其诸多高级特性,如动静分离、Gzip资源压缩、HTTP缓存配置、IP黑白名单、以及基于Keepalived的高可用保障机制等。

二、Nginx环境搭建(Linux CentOS示例)

下面是在Linux环境下安装Nginx的步骤:
创建Nginx安装目录并进入
下载Nginx安装包: 您可以通过FTP工具上传预先下载的离线安装包,或者使用wget命令在线获取。
如果系统中没有wget命令,可以通过yum安装:
解压Nginx压缩包
安装Nginx所需的依赖库和包: Nginx编译安装需要GCC编译器、PCRE库(用于支持正则表达式)、zlib库(用于Gzip压缩)和OpenSSL库(用于支持HTTPS)。
如果您需要在离线环境安装,可以先下载这些依赖的RPM包:
notion image
配置Nginx编译选项: 进入解压后的Nginx源码目录,执行configure脚本。--prefix指定Nginx的安装路径。
这里我将安装目录指定为/soft/nginx/nginx-install,以区分源码目录。
编译并安装Nginx
检查安装结果: 安装完成后,进入指定的安装目录(本例中为/soft/nginx/nginx-install),ls查看生成的文件结构,主要关注conf (配置文件目录)、html (默认站点根目录)、logs (日志目录)、sbin (可执行文件目录)。
修改Nginx核心配置文件: 编辑安装目录下的conf/nginx.conf文件。
找到server块,至少修改以下两项:
例如,修改为 server_name localhost; 或实际IP。
启动Nginx并验证: 使用 -c 参数指定配置文件启动Nginx。
Nginx常用操作命令 (均在Nginx安装目录下执行,如/soft/nginx/nginx-install):
开放防火墙端口: 如果系统启用了防火墙(如firewalld),需要开放Nginx监听的端口(默认为80)。
浏览器访问测试
: 在本地Windows或Mac的浏览器中,输入Nginx服务器的IP地址(或配置的域名)。如果看到Nginx的欢迎页面,则表示安装成功。
notion image

三、Nginx核心功能:反向代理与负载均衡实战

3.1. 准备后端Web服务

我们使用SpringBoot + Freemarker快速搭建一个简单的Web项目 (项目名:springboot-web-nginx),用于演示。
IndexNginxController.java
这个Controller会获取当前应用实例的端口号,并在访问根路径 / 时,将其传递给 index.ftl 模板。
src/main/resources/templates/index.ftl (Freemarker模板):
模板会显示来自哪个端口的服务响应了请求。

3.2. 配置Nginx实现负载均衡

修改nginx.conf配置文件,添加upstream块来定义后端服务器集群,并在server块的location中配置代理。
部署说明
  1. 将上述SpringBoot项目打成jar包。
  1. 在两台服务器(或同一台服务器的不同端口)上分别启动该项目。
      • 第一个实例:修改application.properties,设置server.port=8080
      • 第二个实例:修改application.properties,设置server.port=8090
  1. 确保Nginx服务器可以访问到这两个后端服务。
  1. 启动Nginx。
效果演示: 通过浏览器访问Nginx的IP地址(或域名)。多次刷新页面,会看到页面上显示的端口号在8080和8090之间切换,并且由于权重设置为1:2,访问8090端口的次数大约是8080的两倍。
notion image

3.3. Nginx请求分发原理

当客户端请求
时:
notion image
  1. 请求到达Nginx服务器,Nginx监听80端口。
  1. Nginx根据server_name匹配到对应的server块。
  1. 根据请求路径/匹配到location / {}规则。
  1. proxy_pass http://nginx_boot_cluster;指令将请求转发到名为nginx_boot_clusterupstream
  1. Nginx根据upstream中定义的服务器列表和负载均衡策略(默认轮询,本例中考虑权重)选择一台后端服务器(如192.168.0.100:8080192.168.0.100:8090),并将请求转发过去。

四、Nginx动静分离:提升性能的关键策略

动静分离是将网站的动态内容(如JSP、PHP、Node.js应用生成的页面)和静态内容(如HTML、CSS、JavaScript文件、图片、视频等)分开处理和部署的优化手段。
为什么需要动静分离?
以淘宝首页为例:
notion image
访问淘宝首页时,浏览器会发起上百个请求。如果所有这些请求(包括大量静态资源请求)都由后端的Web应用服务器(如Tomcat)处理,将对其造成巨大压力。
notion image
事实上,这些请求中大部分是针对
等静态资源的。这些资源通常不经常变动。如果让Nginx直接处理这些静态资源请求,而不转发到后端应用服务器,可以:
  • 大幅减轻后端服务器的并发压力。
  • 提高静态资源的响应速度(Nginx处理静态文件非常高效)。
  • 更方便地对静态资源进行缓存、压缩等优化。
实现动静分离步骤:
  1. 创建静态资源存放目录: 在Nginx服务器上创建一个专门存放静态资源的目录,例如 /soft/nginx/static_resources/
    1. 迁移静态资源: 将项目中的所有静态资源(如css/nginx_style.css, js/jquery.js等)拷贝到上述Nginx服务器的静态资源目录中。 然后,从后端Web应用项目中移除这些静态资源,重新打包部署Web应用。
    1. 修改Nginx配置: 在nginx.confserver块中,添加一个或多个location块来匹配静态资源请求,并指定其根目录。
      1. location ~* \\.(html|...|css)$ 解析:
        • location: Nginx配置块关键字。
        • ~*: 表示进行不区分大小写的正则表达式匹配。
        • \\.: 匹配实际的点.(因为.在正则中有特殊含义,需要转义)。
        • (html|htm|...|css): 匹配括号内任一后缀。
        • $: 匹配字符串结尾。
        • 综述:此规则匹配所有以指定静态文件后缀结尾的请求。
    1. 重启Nginx并测试:即使后端项目的static目录下的nginx_style.css文件已被移除,页面样式依然有效,说明Nginx成功提供了该静态文件。
      1. 启动移除了静态资源的Web服务。访问页面,检查开发者工具,确认静态资源(如CSS、JS、图片)请求是由Nginx直接响应的(通常响应头中会有Nginx相关信息,且响应速度更快),而不是由后端应用服务器响应。
        notion image
        notion image
    替代方案:也可以将静态资源上传到CDN或专门的文件存储服务(如OSS、S3),然后在Nginx中配置proxy_pass指向这些服务,或者直接在前端HTML中引用CDN地址。

    五、Nginx Gzip资源压缩:节省带宽,加速传输

    在动静分离的基础上,如果静态资源文件体积越小,传输速度自然越快,同时也更节省网络带宽。Nginx可以通过Gzip压缩算法在传输静态资源前对其进行压缩,从而:
    • 减少传输数据量,节省带宽。
    • 加快资源加载速度,提升用户体验和系统吞吐量。
    Nginx提供了三个与Gzip相关的模块:ngx_http_gzip_module (内置, 主要使用)、ngx_http_gzip_static_module (预压缩静态文件)、ngx_http_gunzip_module (解压)。我们将主要使用ngx_http_gzip_module提供的指令。
    Gzip压缩配置指令详解:
    参数项
    释义
    示例值/默认值
    gzip
    开启或关闭Gzip压缩功能。
    on / off (默认off)
    gzip_types
    指定对哪些MIME类型的文件进行压缩。
    text/plain application/javascript text/css image/svg+xml (默认text/html)
    gzip_comp_level
    压缩级别 (1-9)。 级别越高,压缩率越好,但消耗CPU越多。通常设为5或6。
    1-9 (默认1)
    gzip_vary
    是否在响应头中添加Vary: Accept-Encoding 建议开启,帮助代理服务器正确缓存。
    on / off (默认off)
    gzip_buffers
    设置处理压缩请求时使用的缓冲区数量和大小。
    16 8k (数量 大小)
    gzip_disable
    针对特定User-Agent禁用Gzip。 例如,某些旧版IE浏览器对Gzip支持不佳。
    MSIE [1-6]\\.
    gzip_http_version
    启用Gzip所需的最低HTTP协议版本。
    1.0 / 1.1 (默认1.1)
    gzip_min_length
    触发压缩的文件最小体积。 小于此值的文件不进行压缩(压缩小文件可能得不偿失)。
    20 (字节,默认20)
    gzip_proxied
    当Nginx作为反向代理时,对后端服务器响应启用Gzip的条件。
    off / any / expired
    nginx.confhttp块中配置Gzip:
    gzip_proxied 选项详解:
    • off: 关闭对后端响应的压缩。
    • expired: 如果后端响应头中包含Expires信息且已过期,则开启压缩。
    • no-cache: 如果后端响应头中包含Cache-Control: no-cache,则开启压缩。
    • no-store: 如果后端响应头中包含Cache-Control: no-store,则开启压缩。
    • private: 如果后端响应头中包含Cache-Control: private,则开启压缩。
    • no_last_modified: 如果后端响应头中不包含Last-Modified,则开启压缩。
    • no_etag: 如果后端响应头中不包含ETag,则开启压缩。
    • auth: 如果后端响应头中包含Authorization,则开启压缩。
    • any: 无条件对所有来自后端服务器的响应启用压缩。
    测试Gzip压缩效果: 在Web项目中引入一个较大的JS文件,例如jquery-3.6.0.js
    对比开启Gzip压缩前后的文件大小:
    notion image
    从图中可见,未开启Gzip时,JS文件原始大小为230KB。配置并重启Nginx后,启用Gzip压缩,文件大小显著减小到69KB,压缩效果非常明显!
    注意事项:
    1. 对于图片(如JPEG, PNG, GIF)和视频文件,它们通常已经是高度压缩的格式。再次对它们进行Gzip压缩,效果甚微,甚至可能因为Gzip头部信息而略微增加文件大小,并白白消耗CPU资源。因此,gzip_types中一般不包含这些图片和视频的MIME类型。
    1. 对于JavaScript文件,应指定其MIME类型为application/javascripttext/javascriptapplication/x-javascript 是旧的或非标准的类型。

    六、Nginx请求与响应缓冲区(Buffers)

    当Nginx作为反向代理时,它在客户端和后端服务器之间建立了两个独立的连接:客户端 <-> NginxNginx <-> 后端服务器。这两个连接的网络速度、处理能力可能不一致。如果后端服务器响应速度快,而客户端接收速度慢,Nginx就需要缓冲 (Buffering) 来自后端的数据,以避免阻塞后端服务器,并平滑地将数据发送给客户端。
    Nginx缓冲区的作用:
    • 解耦速度不匹配:缓解客户端与后端服务器处理速率不一致的问题。
    • 提高效率:Nginx可以先完整接收后端响应,然后再高效地发送给客户端,或者在接收部分数据后就开始向客户端发送。
    • 减少即时传输带宽消耗:通过缓冲,可以更平滑地利用网络带宽。
    缓冲区相关配置指令: 主要针对代理到后端的响应数据(proxy_前缀):
    • proxy_buffering on | off;
      • 是否启用对后端服务器响应的缓冲。 默认on。如果关闭,Nginx会尝试同步地将后端数据转发给客户端,这可能导致后端连接长时间被占用。
    • client_body_buffer_size size;
      • 设置用于缓冲客户端请求体(如POST数据)的内存大小。如果请求体超过此大小,可能会被写入临时文件。
    • proxy_buffers number size;
      • 为每个连接设置用于从后端服务器读取响应的缓冲区的数量和大小。 例如 8 4k 表示8个4KB的缓冲区。默认值通常是 4 4k8 8k,取决于操作系统页面大小。
    • proxy_buffer_size size;
      • 单独设置用于存储后端响应第一部分(通常是响应头)的缓冲区大小。 这个缓冲区必须足够大以容纳所有响应头。默认值通常等于一个proxy_buffers单位的大小。
    • proxy_busy_buffers_size size;
      • 当缓冲区正在向客户端发送数据(处于"busy"状态)时,这些"busy"状态的缓冲区的总大小限制。在未完全接收完后端响应时,Nginx也可以将已接收并处于"busy"状态的缓冲数据发送给客户端。此值通常不应大于 proxy_buffers 总大小减去一个 proxy_buffer 的大小。默认通常是 proxy_buffer_size * 2
    • proxy_temp_path path [level1 [level2 [level3]]];
      • 当内存缓冲区(proxy_buffers)存满时,Nginx可以将超出部分的数据临时写入磁盘文件。此指令设置这些临时文件的存放目录。
      • path:临时目录的路径。
      • levels:临时文件目录的层级结构,例如 1 2 表示创建两级子目录。
    • proxy_temp_file_write_size size;
      • 一次向临时文件写入数据的最大大小。
    • proxy_max_temp_file_size size;
      • 单个连接允许使用的磁盘临时文件的最大总大小。如果超过此限制,可能会导致错误。设为0禁用磁盘临时文件。
    非缓冲相关的超时配置项:
    • proxy_connect_timeout time;
      • Nginx与后端服务器建立连接的超时时间。默认60s
    • proxy_read_timeout time;
      • Nginx从后端服务器读取响应的超时时间(指两次成功读取操作之间的最大间隔,而非整个响应的传输时间)。默认60s
    • proxy_send_timeout time;
      • Nginx向后端服务器发送请求的超时时间(指两次成功写入操作之间的最大间隔)。默认60s
    nginx.confhttp块的缓冲区配置示例:
    注意:上述缓冲区参数是为每个请求/连接独立分配的,并非所有请求共享。具体的参数值需要根据业务特性、服务器内存大小以及平均请求/响应数据大小来综合评估和调整。

    七、Nginx代理缓存机制:提升响应速度,降低后端压力

    缓存 (Caching) 是提升Web应用性能最有效的手段之一。Nginx作为反向代理,可以缓存后端服务器的响应内容。当后续有相同请求到达时,Nginx可以直接从缓存中返回结果,而无需再次请求后端服务器。
    Nginx代理缓存带来的优势:
    • 减少后端请求:显著降低后端服务器的负载和数据库压力。
    • 节省网络带宽:避免重复传输相同数据。
    • 加快响应速度:从Nginx本地缓存读取通常远快于请求后端。
    • 提高系统整体吞吐量和可用性:即使后端短暂故障,Nginx仍可能提供缓存内容(需配置proxy_cache_use_stale)。
    Nginx缓存相关核心配置指令:
    • proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] ...;
      • 定义一个缓存存储区域。 这是配置Nginx缓存的首要步骤,通常放在http块。
      • path: 缓存文件在磁盘上的存储路径。
      • levels: 缓存目录的层级结构,例如 1:2 表示第一级目录用1个字符命名,第二级用2个字符命名(基于缓存键的哈希值)。
      • keys_zone=name:size: 必须指定。 定义一个共享内存区域,用于存储缓存键(cache keys)和元数据(metadata)。name是区域名称,size是内存大小(例如10m,1MB大约可存8000个key)。这个区域用于快速查找缓存。
      • inactive=time: 缓存项在指定时间内未被访问则被视为不活动并可能被移除。例如 60m (60分钟)。默认10分钟。
      • max_size=size: 磁盘缓存区域允许的最大总大小。当达到此限制时,Nginx的缓存管理器进程会根据LRU(最近最少使用)等算法移除旧的缓存项。例如 10g (10GB)。
      • 其他可选参数如 manager_files, manager_sleep, loader_files 等,用于控制缓存管理进程的行为。
      • 语法极长,请参考官方文档 (Nginx Docs: proxy_cache_path)。
    • proxy_cache zone_name | off;
      • serverlocationif块中启用或关闭缓存,并指定使用哪个proxy_cache_path定义的共享内存区域。
      • zone_name: 必须与proxy_cache_pathkeys_zone定义的名称一致。
    • proxy_cache_key string;
      • 定义用于生成缓存键(cache key)的字符串。 缓存键决定了哪些请求被认为是相同的。
      • 常用的组合:$scheme$proxy_host$request_uri (协议+代理主机名+请求URI)。
      • 也可以包含 $is_args$args (是否有参数及参数本身) 来区分带不同参数的同一URI。
      • 默认值:$scheme$proxy_host$uri$is_args$args
    • proxy_cache_valid [code ...] time;
      • 为不同HTTP状态码的响应设置缓存有效期。
      • 例如:proxy_cache_valid 200 302 10m; (200和302状态码缓存10分钟)
      • proxy_cache_valid 404 1m; (404状态码缓存1分钟)
      • proxy_cache_valid any 5m; (其他所有状态码缓存5分钟)
    • proxy_cache_min_uses number;
      • 资源至少被请求多少次后才会被缓存。默认1。设置大于1可以避免缓存不常用的资源。
    • proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;
      • 当与后端服务器通信发生错误或超时时,是否允许Nginx使用过期的(stale)缓存项作为响应。 这是一个非常有用的特性,可以提高系统在后端故障时的可用性。
      • 例如:proxy_cache_use_stale error timeout updating http_500 http_502;
    • proxy_cache_lock on | off;
      • 缓存锁。 当多个相同的请求(基于proxy_cache_key)同时到达且缓存未命中或已过期时,启用此项可以只允许第一个请求去后端获取数据并更新缓存,其他相同请求则等待缓存更新或锁超时。防止“缓存风暴”。默认off
    • proxy_cache_lock_timeout time;
      • proxy_cache_lock的超时时间。如果第一个请求在指定时间内未更新缓存,则后续等待的请求将被允许直接发往后端。默认5s
    • proxy_cache_methods GET | HEAD | POST ...;
      • 指定对哪些HTTP方法的请求启用缓存。 默认只缓存GETHEAD请求。如果需要缓存POST请求的响应(需谨慎评估幂等性),可以添加POST
    • proxy_no_cache string ...;
      • 定义不将响应存入缓存的条件。如果任一字符串参数值不为空且不为"0",则响应不会被缓存。
      • 例如:proxy_no_cache $cookie_nocache $arg_nocache; (如果cookie或URL参数中包含特定标志,则不缓存)。
    • proxy_cache_bypass string ...;
      • 定义不从缓存中读取响应(即直接穿透到后端)的条件。如果任一字符串参数值不为空且不为"0",则Nginx会忽略缓存,直接请求后端。
    • add_header X-Cache-Status $upstream_cache_status;
      • 在响应头中添加一个自定义字段,显示缓存命中状态。$upstream_cache_status是Nginx内置变量。
      • $upstream_cache_status 的可能值:
        • MISS: 请求未命中缓存,响应从后端获取。
        • HIT: 请求命中有效缓存。
        • EXPIRED: 命中缓存但已过期,Nginx将请求后端并更新缓存(如果后端允许)。
        • STALE: 命中了过期的缓存,但根据proxy_cache_use_stale配置被允许使用。
        • REVALIDATED: Nginx通过条件请求(如If-Modified-Since)向后端验证了过期缓存仍然有效。
        • UPDATING: 命中了过期缓存,但另一个请求正在更新它(当proxy_cache_lock启用时)。
        • BYPASS: 根据proxy_cache_bypass配置,响应被强制从后端获取。
    Nginx代理缓存配置示例 (nginx.conf):
    测试缓存效果:
    notion image
    首次访问,
    应为
    。由于配置了
    ,前三次访问都可能是
    。第四次及以后访问(在缓存有效期内),状态应变为

    7.1. Nginx缓存清理

    当缓存文件过多导致磁盘空间不足时,Nginx的缓存管理器会自动清理。但有时我们需要手动或通过API方式精确清理特定缓存。
    手动清理:直接删除proxy_cache_path指定的缓存目录下的文件。不推荐在生产环境频繁操作。
    ngx_cache_purge第三方模块: 对于开源版Nginx,可以使用第三方模块 ngx_cache_purge 来实现通过HTTP请求清除缓存的功能。商业版Nginx Plus内置了此功能。
    安装 ngx_cache_purge 模块(以源码编译方式为例):
    1. 下载模块源码
      1. 重新编译Nginx并添加模块: 你需要回到Nginx的源码目录(例如 /soft/nginx/nginx-1.21.6),在执行./configure时通过-add-module指向ngx_cache_purge模块的源码路径。
        1. 编译,但不要 make install
          1. make install会覆盖现有安装,我们只需要新的Nginx可执行文件。
        1. 替换旧的Nginx可执行文件: 备份旧的nginx可执行文件,然后将新编译的(位于源码目录下的objs/nginx)复制过去。
          1. 配置Nginx以使用缓存清除功能: 在nginx.conf中添加一个新的location块来处理清除请求。
            1. 重启Nginx。之后就可以通过访问 http://example.com/purge/path/to/clear (其中/path/to/clear是你希望清除缓存的原始URI) 来清除特定缓存了。

            八、Nginx实现IP黑白名单访问控制

            有时需要限制特定IP地址的访问权限:
            • 白名单:只允许指定的IP或IP段访问某些资源或整个站点。
            • 黑名单:禁止恶意IP或爬虫访问。
            Nginx通过http_access_module模块的allowdeny指令实现此功能。
            基本用法:
            规则按顺序匹配,第一个匹配到的规则生效。
            使用单独文件管理IP列表: 当IP列表很长时,将其写在主配置文件中不方便管理。可以创建单独的.conf文件存放IP列表,然后在主配置中include它们。
            创建BlocksIP.conf (黑名单):
            创建WhiteIP.conf (白名单,通常用于特定路径):
            nginx.conf中引用:
            include指令可以放在http, server, 或 location块中,作用范围不同。
            更高级的IP访问控制: 可以使用ngx_http_geo_module模块根据客户端IP地址的地理位置(国家、地区)进行访问控制,但这需要IP地理数据库。

            九、Nginx解决跨域问题 (CORS)

            跨域资源共享 (Cross-Origin Resource Sharing, CORS) 是一个W3C标准,它允许浏览器向不同源(协议、域名、端口任一不同)的服务器发起XMLHttpRequest或Fetch请求。
            跨域问题产生的原因: 浏览器的同源策略 (Same-Origin Policy) 出于安全考虑,默认禁止脚本从一个源加载的文档或脚本去与另一个源的资源进行交互。这限制了XMLHttpRequest、Fetch API等发起的跨域HTTP请求。
            Nginx作为反向代理解决跨域: 通过在Nginx层面添加特定的CORS响应头,可以告知浏览器允许跨域请求。
            注意
            • always参数确保即使在错误响应(如4xx, 5xx)中也添加这些头部。
            • 如果后端应用本身也处理CORS头部,可能会造成冲突。应协调仅由一方(Nginx或后端)处理。通常在Nginx层面统一处理更方便。
            • 对于分布式架构中的RPC调用,如果它们之间也通过HTTP且存在跨域(不常见),可能也需要类似的CORS处理,但这更多是服务间通信配置的问题。

            十、Nginx防盗链设计

            盗链 (Hotlinking) 是指其他网站直接在其页面中链接并显示你网站上的资源(如图片、视频),从而消耗你服务器的带宽和资源,而访问者却是在对方网站上。
            Nginx防盗链原理: 利用HTTP请求头中的Referer字段。Referer记录了发起当前请求的页面的URL。Nginx可以检查Referer头,如果它不属于本站域名或允许的域名列表,则拒绝访问或返回特定内容(如一张警告图片)。
            Nginx使用ngx_http_referer_module模块的valid_referers指令实现防盗链。
            valid_referers指令语法:valid_referers none | blocked | server_names | string ...;
            • none: 允许Referer头为空的请求(例如,直接在浏览器地址栏输入图片URL)。
            • blocked: 允许Referer头存在但格式无效(非标准URL)的请求。
            • server_names: 允许Referer头中的域名与当前server_name指令配置的域名匹配的请求。
            • string: 允许指定的域名或IP,支持通配符 (如 .example.com) 和正则表达式 (以~开头)。
            配置示例:
            注意Referer头可以被客户端伪造,因此防盗链并非100%可靠,但能有效阻止大部分普通盗链行为。

            十一、Nginx大文件传输配置优化

            在需要通过Nginx代理传输大文件(如文件上传或下载)的场景中,可能会遇到默认配置不足导致的问题,如请求体超限、连接超时等。
            相关配置项:
            配置项
            释义
            默认值 (可能因版本不同)
            client_max_body_size
            允许的客户端请求体的最大体积。 上传大文件时必须调大此值。
            1m
            client_header_timeout
            Nginx等待客户端发送完整请求头的超时时间。
            60s
            client_body_timeout
            Nginx读取客户端请求体的超时时间(指两次成功读取操作间的间隔)。
            60s
            proxy_read_timeout
            Nginx从后端服务器读取响应的超时时间(两次成功读取操作间的间隔)。下载大文件时可能需要调大。
            60s
            proxy_send_timeout
            Nginx向后端服务器发送请求的超时时间(两次成功写入操作间的间隔)。
            60s
            配置示例 (httpserverlocation块中):
            注意
            • 这些配置只是调整了Nginx作为代理层的限制。大文件传输的最终瓶颈和处理逻辑仍在后端应用服务器。
            • Nginx也可以通过第三方模块(如nginx-upload-module)直接作为文件上传服务器,但这通常适用于特定简单场景。对于复杂或频繁的文件操作,建议使用专门的文件服务器,并由后端应用处理上传/下载逻辑。

            十二、Nginx配置SSL证书实现HTTPS

            随着网络安全意识的提高,HTTPS已成为现代网站的标配。当Nginx作为网站入口时,SSL证书也应在Nginx层面配置。
            配置SSL证书步骤:
            1. 获取SSL证书: 从受信任的CA(证书颁发机构)购买或申请免费SSL证书(如Let's Encrypt)。审核通过后,下载适用于Nginx的证书文件。通常包含:
                • 证书文件.crt.pem (通常是 fullchain.pem,包含服务器证书和中间证书链)。
                • 私钥文件.key (服务器私钥,必须妥善保管)。
            1. 上传证书到服务器: 在Nginx服务器上创建一个目录(如 /etc/nginx/ssl//soft/nginx/nginx-install/conf/certs/),并将证书文件和私钥文件上传到此目录。确保私钥文件的权限安全(例如 chmod 600 private.key)。
            1. 修改Nginx配置 (nginx.conf): 添加一个新的server块来监听443端口 (HTTPS默认端口),并配置SSL相关指令。
              1. 测试配置并重启Nginx
                1. 访问 https://your_domain.com,检查浏览器地址栏是否显示安全锁标志。

              十三、Nginx高可用方案:Keepalived + 双机热备

              单节点Nginx虽然性能高,但仍存在单点故障风险(如硬件故障、系统崩溃)。为保障Nginx层的高可用,常用Keepalived结合**双机热备(主备模式)**方案。
              Keepalived是一个基于VRRP协议(虚拟路由冗余协议)的路由热备软件,它通过虚拟IP (Virtual IP, VIP) 实现高可用。集群中多台Nginx服务器共享一个VIP,但通常只有一台主服务器(MASTER)实际绑定并对外提供服务。当主服务器故障时,Keepalived会自动将VIP漂移到备用服务器(BACKUP),由备用服务器接管服务,从而实现故障切换。

              13.1. Keepalived安装与配置

              1. 在主备两台Nginx服务器上都安装Keepalived
                1. 注意--sysconfdir=/etc 会将配置文件默认放到 /etc/keepalived/keepalived.conf
              1. 创建Nginx健康检查及重启脚本 (/etc/keepalived/check_nginx_status.sh): 此脚本由Keepalived定时调用,用于检测Nginx进程是否存活,如果不存在则尝试重启Nginx。若重启失败,Keepalived会认为Nginx故障,可能触发主备切换。
                1. 赋予脚本执行权限并修改编码(如果需要):
              1. 配置主Nginx服务器的Keepalived (/etc/keepalived/keepalived.conf):
                1. 配置备Nginx服务器的Keepalived (/etc/keepalived/keepalived.conf): 与主服务器配置类似,但关键区别在于statepriority
                  1. 启动Keepalived服务并设置开机自启 (在主备两台服务器上)
                    1. 测试VIP是否生效: 在主服务器上使用ip addr命令,应能看到VIP(如192.168.1.100)已绑定到指定的网络接口。备服务器上此时不应有此VIP。 从外部网络ping VIP,应能ping通(指向主服务器)。
                      1. notion image
                        notion image

                    13.2. Nginx高可用性测试

                    1. Nginx宕机自动重启测试
                        • 在主服务器上,手动停止Nginx服务 (/soft/nginx/nginx-install/sbin/nginx -s stop)。
                        • 观察/var/log/keepalived_nginx_check.log日志,应能看到check_nginx_status.sh脚本检测到Nginx停止并尝试重启。
                        • 稍等片刻,使用ps aux | grep nginx检查Nginx进程是否已自动恢复。VIP此时不应发生漂移。
                          • notion image
                    1. 主服务器故障,VIP漂移测试
                        • 在主服务器上,模拟服务器故障,例如停止Keepalived服务 (systemctl stop keepalived) 或直接关闭主服务器。
                        • 在主服务器上使用ip addr,会发现VIP消失。
                          • notion image
                        • 切换到备用服务器,使用ip addr,应能看到VIP已成功漂移到备用服务器的网络接口上。
                          • notion image
                        • 此时,所有通过VIP访问的请求都会被备用服务器上的Nginx处理。
                    重要:Nginx的nginx.conf中,server_name应配置为VIP对应的域名,或者直接使用VIP地址(但不推荐直接用IP)。客户端通过域名访问时,DNS解析应指向VIP。
                    通过Keepalived实现的Nginx主从热备,能有效应对单点Nginx宕机或服务器故障,确保对外服务的连续性和高可用性,实现7x24小时不间断服务。

                    十四、Nginx性能优化核心策略

                    Nginx本身性能已非常出色,但通过合理的配置优化,可以进一步挖掘其潜力。影响性能的因素众多(网络、硬件、操作系统、后端服务、应用本身、数据库等),这里仅列举一些针对Nginx本身的高收益优化项。

                    14.1. 优化一:开启与后端的HTTP长连接 (Upstream Keepalive)

                    Nginx作为反向代理与后端服务器通信时,使用长连接可以减少频繁建立TCP连接的开销,降低延迟,提高吞吐量。 在upstream块中配置:

                    14.2. 优化二:启用零拷贝 (Sendfile)

                    零拷贝 (Zero-copy) 技术允许数据直接从磁盘文件复制到网络套接字,而无需在内核空间和用户空间之间多次拷贝,极大地提高了文件传输效率,尤其适用于Nginx提供静态文件服务的场景。 在httpserver块中开启:
                    传统方式与零拷贝方式的数据路径对比:
                    • 传统方式:硬件(磁盘) -> 内核缓冲区 -> 用户空间缓冲区(应用) -> 内核套接字缓冲区 -> 网络硬件
                    • 零拷贝方式 (sendfile):硬件(磁盘) -> 内核缓冲区 (直接映射或传递) -> 内核套接字缓冲区 -> 网络硬件 明显减少了数据拷贝次数和上下文切换。

                    14.3. 优化三:TCP传输优化 (tcp_nodelay 和 tcp_nopush)

                    这两个参数控制TCP/IP协议栈的行为,影响数据包的发送时机。
                    • tcp_nopush on;:通常与sendfile on;一起使用。它告诉Nginx在内核层面尽可能将响应头和数据体一起发送,或者累积到一定大小(一个MTU)再发送,以提高网络效率,适合大文件传输。
                    • tcp_nodelay on;:禁用TCP的Nagle算法。Nagle算法会缓存小数据包并尝试合并它们,这可能导致小数据请求的延迟。开启tcp_nodelay(即禁用Nagle)可以使小数据包立即发送,降低延迟,适合交互性强的应用。
                    选择
                    • 如果应用对实时性要求高(如IM、在线游戏、金融交易),且客户端与Nginx之间是长连接,建议开启tcp_nodelay on;
                    • 如果应用主要提供大文件下载或静态内容服务,追求高吞吐和网络效率,建议开启sendfile on;tcp_nopush on;
                    • 注意tcp_nodelaytcp_nopush 在某些情况下可能是互斥的或效果叠加。通常,tcp_nopush用于优化sendfile传输,而tcp_nodelay用于优化动态内容或小数据的即时响应。两者可以同时设置为on,Nginx会根据上下文智能处理。

                    14.4. 优化四:调整Worker工作进程数与连接数

                    Nginx采用多进程(Master-Worker)架构。Master进程负责管理Worker进程,Worker进程实际处理客户端请求。
                    • worker_processes number | auto;
                      • 设置Worker进程的数量。auto会让Nginx根据CPU核心数自动设置。通常设置为CPU核心数,或者略小于核心数(例如,如果CPU有8核,可以设为4或8)。
                      • 过多的Worker进程并不会带来线性性能提升,反而可能因竞争资源和上下文切换导致性能下降。一般不超过8-16个。
                    • worker_rlimit_nofile number;
                      • 设置每个Worker进程能打开的最大文件描述符数量。这个值应大于worker_connections乘以一个系数(因为每个连接可能需要多个文件描述符,如socket、日志文件等)。
                      • 需要同时调整操作系统的文件描述符限制(ulimit -n)。
                    • events { worker_connections number; }
                      • events块中,设置每个Worker进程允许的最大并发连接数。
                      • Nginx总的最大并发连接数理论上是 worker_processes * worker_connections (但还受限于系统资源和文件描述符限制)。

                    14.5. 优化五:开启CPU亲和性 (Worker CPU Affinity)

                    CPU亲和性是指将特定的Worker进程绑定到特定的CPU核心上运行。这可以减少进程在不同CPU核心间切换的开销,提高缓存命中率,从而提升性能,尤其在高并发场景下。
                    worker_cpu_affinity的值是一个位掩码。auto参数(如果Nginx版本支持)可以自动处理绑定。

                    14.6. 优化六:使用高效的I/O模型 (如epoll)

                    Nginx支持多种I/O多路复用模型(如select, poll, epoll, kqueue, devpoll)。在Linux系统上,epoll 是最高效的模型,能处理大量并发连接。 在events块中配置:
                    在FreeBSD上使用kqueue,Solaris上使用devpolleventport。Nginx通常会自动选择当前操作系统上最高效的模型。
                    通过综合运用这些优化策略,并结合具体业务场景进行细致调优,可以使Nginx发挥出极致性能,为Web应用提供坚实、高效的接入层保障。
                    上一篇
                    uniapp 安卓、iOS权限判定uni-app 跨平台应用权限管理SDK (iOS/Android) 深度解析与实战
                    下一篇
                    Vue后台管理系统权限控制详解:从RBAC到动态路由与按钮级权限实