Nginx核心架构、配置详解与性能调优实战指南

1. 项目概述:为什么每个开发者都应该懂点Nginx

如果你在互联网行业待过一段时间,无论你是后端开发、运维还是前端,大概率都听过或者用过Nginx。它就像一个数字世界的交通警察,默默站在你的服务器前面,指挥着成千上万的网络请求,决定谁该去哪、谁该等、谁该被拒绝。很多人对Nginx的印象停留在“一个高性能的Web服务器”,这没错,但它能做的远不止于此。从简单的静态文件服务,到复杂的负载均衡、反向代理、API网关,甚至是安全防护和流量整形,Nginx几乎成了现代Web架构中不可或缺的基石。

我最早接触Nginx是在一个流量突然暴增的项目里,Apache服务器在并发连接数超过几百后就变得异常缓慢,页面加载时间从毫秒级飙升到秒级。在几乎绝望的时候,团队决定尝试用Nginx替换掉一部分前端流量分发的工作。结果令人震惊:同样的硬件配置,Nginx轻松扛住了数千的并发连接,CPU和内存使用率还低得惊人。自那以后,无论是个人项目还是公司系统,Nginx都成了我的首选“守门员”。

这篇文章,我想从一个实践者的角度,和你系统地聊聊Nginx。我不会只给你一堆冷冰冰的命令列表,那样和看官方手册没什么区别。我会结合我这些年踩过的坑、总结的经验,带你理解Nginx的核心设计思想,掌握那些真正高频、实用的命令和配置技巧。目标是让你看完后,不仅能操作,更能明白背后的“为什么”,在遇到问题时能有清晰的排查思路,而不仅仅是机械地复制粘贴。

2. Nginx核心架构与设计哲学

在深入命令和配置之前,我们必须先理解Nginx的“灵魂”。它的高性能并非偶然,而是其独特架构设计的必然结果。理解这一点,后续的所有配置和优化行为才会变得有理有据。

2.1 事件驱动与非阻塞IO:高并发的基石

与Apache传统的“多进程/多线程-每连接”模型不同,Nginx采用了一种 事件驱动 的异步非阻塞架构。你可以把它想象成一个极其高效的餐厅服务员(Master进程)。这个服务员不是一对一地为每张桌子(客户端连接)服务,而是站在餐厅中央,时刻关注着所有桌子的状态。

当A桌举手要点菜(客户端发起请求),服务员记下需求后,并不等待厨房做完,而是立刻转向B桌,看看B桌是否需要结账或加水。厨房(工作进程)做好菜后,会发出一个“事件通知”,服务员接收到通知,再把菜端给A桌。在这个过程中,服务员(Nginx)的线程永远不会因为等待某个慢操作(如IO读写、网络传输)而阻塞住,他永远在处理“已经就绪”的事件。

这就是 非阻塞IO 事件驱动 的精髓。Nginx使用如 epoll (Linux)、 kqueue (BSD)这样的系统调用,来监听大量文件描述符(连接)上的事件。当某个连接的数据准备好读写时,操作系统会通知Nginx,Nginx才会去处理它。这种模型使得一个Nginx工作进程可以轻松维持数万个并发连接,而内存和CPU开销增长却非常平缓。

注意 :这种架构也决定了Nginx在处理动态内容(如PHP、Python)时的局限性。Nginx本身不擅长执行外部程序,它通常将这类请求“代理”给后端的应用服务器(如uWSGI、Gunicorn、PHP-FPM)处理,自己只负责高效的网络调度。所以, Nginx强于“转发”和“调度”,弱于“执行”

2.2 多进程模型:稳定与隔离的保障

Nginx启动后,会有一个 Master进程 和多个 Worker进程

  • Master进程 :以 root 权限运行,负责管理。它不处理任何客户端请求,只做三件事:读取并验证配置、管理Worker进程的生命周期(启动、停止、平滑重启)、接收外部命令(如重载配置)。
  • Worker进程 :以普通用户(如 www-data , nginx )运行,这才是真正处理网络请求、执行业务的“苦力”。多个Worker进程之间相互独立,共享监听端口(通过SO_REUSEPORT),一个进程崩溃不会影响其他进程,极大地提高了稳定性。

这种设计的优势很明显:

  1. 权限隔离 :Worker进程以低权限运行,即使被攻破,危害也相对有限。
  2. 进程隔离 :一个Worker进程的异常(如内存泄漏、第三方模块崩溃)不会波及其他进程。
  3. 充分利用多核CPU :每个Worker进程可以绑定到一个CPU核心,减少上下文切换,提升性能。通常建议Worker进程数设置为与CPU核心数相等或稍多。

2.3 配置文件的上下文与继承关系

Nginx的配置文件(通常是 nginx.conf )采用一种分层的、基于上下文的指令系统。理解这个结构是灵活配置的关键。主要上下文有:

  • main :全局上下文,在配置文件最外层。设置影响整个系统的参数,如worker进程数、用户、错误日志路径等。
  • events :配置事件驱动模型相关的参数,如每个Worker进程的最大连接数。
  • http :定义所有HTTP服务器相关的配置。这是最常用的上下文。
  • server :在 http 上下文内,用于定义一个虚拟主机(一个网站或服务)。
  • location :在 server 上下文内,用于匹配特定的URI(请求路径),并定义如何处理匹配到的请求。

指令的生效范围遵循“子上下文继承父上下文,子上下文可覆盖父上下文”的原则。例如,在 http 块中设置的 gzip on; 会被所有 server 继承,但某个特定的 server location 可以将其覆盖为 gzip off;

3. 核心配置文件详解与最佳实践

默认的 nginx.conf 文件可能看起来有点复杂,但拆开看,它是由多个逻辑清晰的块组成的。我们以一个优化后的、生产环境可用的配置骨架为例,逐段解析。

3.1 全局配置(main上下文)

# 定义运行Nginx的用户和组。出于安全,务必使用非root用户。
user nginx;

# Worker进程数。最优值通常等于或略多于CPU核心数。
# 可以通过命令 `grep processor /proc/cpuinfo | wc -l` 获取核心数。
worker_processes auto; # 使用auto让Nginx自动检测。

# 定义错误日志的路径和级别。级别从低到高:debug, info, notice, warn, error, crit。
# 生产环境通常用warn或error,调试时可用info或debug。
error_log /var/log/nginx/error.log warn;

# 存储Master进程ID的文件路径。用于向Nginx发送信号。
pid /var/run/nginx.pid;

# 每个Worker进程能打开的最大文件描述符数量。受系统限制。
# 需要与系统的 `ulimit -n` 值协调。高并发场景下需要调大。
worker_rlimit_nofile 65535;

实操心得 worker_processes 设置为 auto 是个好习惯。但要注意,如果你的服务器上还运行着其他重要服务(如数据库),可能需要手动设置少一些,为其他服务预留CPU资源。

3.2 事件模块配置(events上下文)

events {
    # 每个Worker进程同时处理的最大连接数。
    # 这个值乘以worker_processes就是Nginx能处理的总并发连接数上限。
    worker_connections 10240;

    # 使用epoll这种高效的多路复用IO方法(Linux特有)。
    use epoll;

    # 开启“惊群”问题优化。当有新连接到来时,只唤醒一个Worker进程,而不是全部。
    accept_mutex on;

    # 设置Worker进程接收新连接的顺序。on为轮流,off为争抢。高并发下off性能可能更好。
    multi_accept on;
}

避坑指南 worker_connections 值不能随意设置得巨大。总连接数上限还受到系统级限制( net.core.somaxconn )和进程级限制( worker_rlimit_nofile )的约束。一个常见的误区是只调大了Nginx配置,却忘了调整系统参数,导致性能瓶颈。

3.3 HTTP核心配置(http上下文)

http 块是配置的主体,内容最多。我们分段来看。

3.3.1 基础与优化参数

http {
    # 包含MIME类型映射文件。告诉Nginx不同文件后缀对应的Content-Type。
    include /etc/nginx/mime.types;
    # 默认MIME类型。如果找不到对应类型,使用这个(通常是二进制流)。
    default_type application/octet-stream;

    # 定义日志格式。main是这个格式的名字,可以自定义多个。
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # 指定访问日志的路径和使用的格式。
    access_log /var/log/nginx/access.log main;

    # 核心优化:开启高效文件传输模式。
    # sendfile允许在内核空间直接完成文件数据拷贝到socket,绕过用户空间,效率极高。
    sendfile on;
    # 与sendfile配合使用。当数据包小于一定大小时,先缓存再发送,减少网络报文数量。
    tcp_nopush on;
    # 禁用Nagle算法,要求数据立即发送,降低延迟。对于高交互性服务很重要。
    tcp_nodelay on;

    # 保持连接的超时时间。客户端在这个时间内没有发起新请求,连接将被关闭。
    keepalive_timeout 65;
    # 单个保持连接上允许的最大请求数。
    keepalive_requests 100;

    # 隐藏Nginx版本号,增加安全性。
    server_tokens off;

    # 开启Gzip压缩,显著减少文本类资源的传输体积。
    gzip on;
    gzip_min_length 1k; # 小于1k的文件不压缩
    gzip_comp_level 6; # 压缩级别1-9,越高CPU消耗越大,通常6是个平衡点
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on; # 告诉代理服务器缓存压缩和非压缩版本
}

3.3.2 Server虚拟主机配置 这是配置网站的核心部分。一个 http 块内可以有多个 server 块。

server {
    # 监听端口和IP。80是HTTP默认端口。`listen 80 default_server;` 表示这是默认虚拟主机。
    listen 80;
    # 定义该虚拟主机响应的域名。可以写多个,用空格隔开。
    server_name example.com www.example.com;

    # 网站根目录。所有相对路径的请求都会基于这个目录查找文件。
    root /usr/share/nginx/html;

    # 默认的索引文件。当请求以`/`结尾时,Nginx会按顺序尝试寻找这些文件。
    index index.html index.htm;

    # 错误页面定制。当发生404错误时,返回 /404.html 页面,并带上404状态码。
    error_page 404 /404.html;
    location = /404.html {
        internal; # 表示这个location只能被内部重定向访问,不能直接通过URL访问。
    }

    # 最重要的配置块:location。用于匹配请求的URI。
    location / {
        # try_files 指令非常有用:按顺序检查文件或目录是否存在,并返回第一个找到的。
        # $uri 是请求的路径,$uri/ 是将其视为目录。
        # 如果都没找到,最后可以重定向到一个命名的location或返回错误码。
        # 这里如果都没找到,会触发上面的 error_page 404。
        try_files $uri $uri/ =404;
    }

    # 匹配所有以 .php 结尾的请求,用于反向代理到PHP应用服务器。
    location ~ \.php$ {
        # 定义后端服务器的地址。这里指向本机9000端口,通常是PHP-FPM。
        fastcgi_pass 127.0.0.1:9000;
        # 设置FastCGI的一些默认参数。
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params; # 包含一组标准的fastcgi参数配置文件。
    }

    # 禁止访问以点开头的隐藏文件,如 .htaccess, .git
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # 静态资源缓存配置。匹配图片、字体等。
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 30d; # 告诉浏览器缓存30天
        add_header Cache-Control "public, immutable"; # 更精细的缓存控制头
        access_log off; # 静态资源访问日志通常可以关闭,减少磁盘IO
    }
}

配置经验 location 的匹配规则优先级需要牢记: = (精确匹配) > ^~ (前缀匹配,停止正则检查) > ~ ~* (正则匹配,区分/不区分大小写) > / (通用前缀匹配)。错误的顺序会导致配置不生效。一个常见的做法是,先配置精确匹配和静态文件的正则匹配,最后用一个通用的 location / 来处理动态请求或代理。

4. 必备命令行操作与系统管理

光会配置还不够,日常运维和排查问题离不开命令行。Nginx通过向Master进程发送信号来管理。

4.1 启动、停止与重启

首先,你需要知道Nginx二进制文件的位置,通常在 /usr/sbin/nginx 或通过 which nginx 查找。

  • 测试配置文件语法 这是修改配置后必须做的第一步!

    nginx -t
    

    或者指定配置文件路径:

    nginx -t -c /path/to/your/nginx.conf
    

    输出 syntax is ok test is successful 才表示语法正确。

  • 启动Nginx

    nginx
    

    或使用系统服务(推荐):

    systemctl start nginx    # 启动
    systemctl enable nginx   # 设置开机自启
    
  • 停止Nginx : 快速停止,立即中断所有正在处理的连接:

    nginx -s stop
    

    优雅停止,等待Worker进程处理完当前请求后再退出:

    nginx -s quit
    

    系统服务方式:

    systemctl stop nginx
    
  • 重新加载配置文件 最常用的命令。 Master进程检查配置无误后,会启动新的Worker进程加载新配置,并优雅地关闭旧的Worker进程。实现不停机更新配置。

    nginx -s reload
    

    或:

    systemctl reload nginx
    
  • 重新打开日志文件 :在日志切割(如使用 logrotate )后,需要让Nginx重新打开日志文件,以便向新文件写入。

    nginx -s reopen
    

4.2 进程管理与信号

除了 -s 参数,还可以直接使用 kill 命令向Master进程的PID发送信号,实现更精细的控制。PID文件通常位于 /var/run/nginx.pid

# 1. 查找Master进程PID
cat /var/run/nginx.pid
# 或
ps -ef | grep nginx | grep master

# 2. 发送信号
kill -QUIT <master_pid>   # 等同于 nginx -s quit (优雅停止)
kill -TERM <master_pid>   # 等同于 nginx -s stop (快速停止)
kill -HUP <master_pid>    # 等同于 nginx -s reload (重载配置)
kill -USR1 <master_pid>   # 等同于 nginx -s reopen (重新打开日志)
kill -USR2 <master_pid>   # 平滑升级可执行文件(高级操作)
kill -WINCH <master_pid>  # 优雅关闭Worker进程,用于升级回滚

排查技巧 :当你执行 reload 失败,或者Nginx无响应时,直接使用 kill -QUIT kill -TERM 可能无法解决问题。这时候可以尝试 kill -9 强制杀死Master进程,然后再启动。但这是最后的手段,因为会中断所有正在进行的连接。

4.3 信息查询与调试

  • 查看版本和编译参数

    nginx -V
    

    这个命令会输出详细的版本信息以及编译时加入的模块。在排查“为什么这个指令不生效”时非常有用,因为有些功能需要特定的编译模块支持(比如 stub_status 模块用于状态监控)。

  • 查看默认的配置文件路径

    nginx -t 2>&1 | head -n 2
    

    -t 测试的输出中,第一行会显示测试的配置文件路径。

  • 实时查看错误日志 (调试神器):

    tail -f /var/log/nginx/error.log
    

    当你的配置不生效或服务异常时,错误日志是第一个要查看的地方。

5. 高级配置场景实战解析

掌握了基础,我们来看几个生产中高频出现的复杂场景配置。理解这些,你就能解决80%的Nginx相关问题。

5.1 反向代理与负载均衡

这是Nginx最核心的用途之一。将客户端的请求转发到后端一组应用服务器,并实现负载分发。

http {
    # 1. 定义一个上游服务器组,名字叫 backend_servers
    upstream backend_servers {
        # 负载均衡算法,默认是weighted round-robin(加权轮询)
        # 其他算法:least_conn(最少连接), ip_hash(基于IP哈希保持会话)
        # hash $request_uri consistent; (基于URI哈希)

        server 192.168.1.101:8080 weight=3 max_fails=2 fail_timeout=30s;
        server 192.168.1.102:8080 weight=2;
        server 192.168.1.103:8080 backup; # 备份服务器,只有其他都不可用时才启用

        # 可选:长连接优化,与后端服务器保持的连接池大小
        keepalive 32;
    }

    server {
        listen 80;
        server_name api.myapp.com;

        location / {
            # 2. 将请求代理到上游服务器组
            proxy_pass http://backend_servers;

            # 3. 设置重要的代理头信息
            # 将客户端的真实IP传递给后端,否则后端看到的都是Nginx的IP
            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;

            # 4. 超时与重试配置
            proxy_connect_timeout 5s; # 与后端建立连接的超时时间
            proxy_send_timeout 60s;   # 向后端发送请求的超时时间
            proxy_read_timeout 60s;   # 从后端读取响应的超时时间
            # proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
            # 当遇到配置的错误时,尝试转发给上游组中的下一个服务器

            # 5. 缓冲区优化(针对大响应或慢客户端)
            proxy_buffering on;
            proxy_buffer_size 4k;
            proxy_buffers 8 4k;
            proxy_busy_buffers_size 8k;
        }
    }
}

实操心得 proxy_set_header 至关重要,尤其是 X-Real-IP X-Forwarded-For ,否则后端应用无法获取用户真实IP,会影响日志分析、限流和安全策略。 proxy_buffering 默认是开启的,对于API或文件下载服务,开启缓冲区可以提升Nginx性能,但会稍微增加响应延迟。对于需要流式传输或Server-Sent Events (SSE)的场景,需要将其关闭。

5.2 静态资源分离与浏览器缓存优化

将静态文件(CSS, JS, 图片)的请求与动态请求分离,是提升网站性能的黄金法则。

server {
    listen 80;
    server_name www.myapp.com;
    root /data/www/myapp;

    location / {
        proxy_pass http://backend_app; # 动态请求走代理
        # ... 其他代理配置
    }

    # 专门处理静态资源的location
    location /static/ {
        # 静态资源存放在独立的目录,便于管理
        alias /data/static_assets/;
        # 或者使用 root: location /static/ { root /data/; }

        # 强缓存设置:告诉浏览器在过期前直接使用本地缓存,不发请求
        expires 1y; # 缓存1年
        add_header Cache-Control "public, immutable";

        # 关闭日志,减少IO压力
        access_log off;
        log_not_found off;

        # 文件不存在时,不转发到后端,直接返回404
        try_files $uri =404;
    }

    # 前端单页应用(如Vue, React)的History模式支持
    # 所有非静态文件、非API的请求,都返回index.html,由前端路由处理
    location / {
        try_files $uri $uri/ /index.html;
    }
}

避坑指南 alias root 指令容易混淆。 root 会将 location 的路径附加到指定的目录后,而 alias 则会用指定的目录替换 location 匹配的部分。例如, location /i/ { root /data/w3; } 请求 /i/top.gif 会返回 /data/w3/i/top.gif 。而 location /i/ { alias /data/w3/; } 请求 /i/top.gif 会返回 /data/w3/top.gif

5.3 安全加固与访问控制

Nginx可以作为第一道安全防线。

server {
    # 1. 限制请求方法:只允许GET和POST
    if ($request_method !~ ^(GET|POST|HEAD)$) {
        return 405; # Method Not Allowed
    }

    # 2. 限制特定路径的访问(如管理后台)
    location /admin/ {
        # 基于IP的访问控制
        allow 192.168.1.0/24; # 允许内网网段
        allow 203.0.113.1;    # 允许某个特定IP
        deny all;             # 拒绝其他所有

        # 或者使用HTTP Basic认证
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd; # 使用htpasswd命令生成此文件
        # ... 其他代理配置
    }

    # 3. 防止常见攻击
    # 限制客户端请求体大小,防CC攻击
    client_max_body_size 10m;

    # 限制请求速率(限流)
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        # burst是突发请求队列大小,nodelay表示不延迟处理突发请求,直接拒绝超出的部分
        proxy_pass http://backend_api;
    }

    # 4. 隐藏敏感信息
    # 禁止访问某些文件
    location ~* \.(env|log|sh|sql|key)$ {
        deny all;
        return 404; # 返回404而不是403,隐藏文件存在的信息
    }

    # 5. 添加安全响应头
    add_header X-Frame-Options "SAMEORIGIN" always; # 防点击劫持
    add_header X-Content-Type-Options "nosniff" always; # 防MIME类型嗅探
    add_header X-XSS-Protection "1; mode=block" always; # 启用XSS过滤器(浏览器)
    # 注意:Content-Security-Policy (CSP) 头需要根据你的站点内容仔细配置
}

安全经验 :安全头(Security Headers)的配置非常重要,但 add_header 指令在Nginx中有继承规则: 如果当前块(如 location )设置了 add_header ,那么它会覆盖父块(如 server )中同名的头,而不是合并。 这意味着,如果你在 server 级别设置了安全头,但在某个 location 里设置了其他 add_header (比如CORS头),那么 server 级别的安全头在这个 location 里就会失效!解决方案是,要么在每个需要安全头的 location 里重复设置,要么将不需要安全头的特殊 location 移到单独的 server 块中。

6. 性能调优与监控排查

配置好了,如何知道它运行得好不好?如何进一步压榨性能?

6.1 状态监控模块

Nginx内置了一个简单的状态模块 ngx_http_stub_status_module ,编译时默认通常已包含。

# 在一个单独的server块或内部location中配置
server {
    listen 8080; # 用一个内部端口
    server_name localhost;
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1; # 只允许本机访问,非常重要!
        deny all;
    }
}

访问 http://your-server:8080/nginx_status ,你会看到类似下面的信息:

Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
  • Active connections :当前活跃客户端连接数。
  • accepts :Nginx启动后接受的客户端连接总数。
  • handled :成功处理的连接数。通常与accepts非常接近,如果差异大,说明有些连接在握手阶段就关闭了。
  • requests :客户端发起的请求总数。一个连接上可以有多个请求(HTTP Keep-Alive)。
  • Reading :正在读取请求头的连接数。
  • Writing :正在向客户端写入响应的连接数。
  • Waiting :处于空闲(Keep-Alive)状态的连接数。这是 Active connections 减去前两项。

6.2 连接数优化与系统调优

Nginx的性能瓶颈往往不在自身,而在操作系统限制。

  1. 调整系统文件描述符限制 : Nginx的 worker_connections 受限于单个进程能打开的最大文件数( worker_rlimit_nofile ),而这个值又受系统全局限制。

    # 临时生效
    ulimit -n 65535
    
    # 永久生效,编辑 /etc/security/limits.conf,添加:
    * soft nofile 65535
    * hard nofile 65535
    # 对于Nginx进程用户,可以单独设置:
    nginx soft nofile 65535
    nginx hard nofile 65535
    
  2. 调整网络内核参数 /etc/sysctl.conf ):

    # 增加等待连接队列的最大值
    net.core.somaxconn = 65535
    # 加快TIME_WAIT状态的端口回收(高并发短连接场景)
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1 # 注意:在NAT网络环境下此参数可能导致问题,Linux 4.12+已移除
    # 增加系统全局的端口范围
    net.ipv4.ip_local_port_range = 1024 65000
    # 增加TCP SYN backlog队列大小,防SYN Flood
    net.ipv4.tcp_max_syn_backlog = 262144
    # 增加系统同时保持TIME_WAIT状态套接字的最大数量
    net.ipv4.tcp_max_tw_buckets = 10000
    

    修改后执行 sysctl -p 生效。

6.3 日志分析与问题排查

访问日志和错误日志是排查问题的生命线。

  • 分析访问日志,找到慢请求

    # 使用awk找出响应时间最长的请求(假设日志格式中包含$request_time)
    awk '{print $NF, $0}' /var/log/nginx/access.log | sort -rn | head -20
    # $NF 通常代表最后一个字段,在配置了`$request_time`时就是响应时间
    
  • 实时监控错误日志中的严重错误

    tail -f /var/log/nginx/error.log | grep -E "(emerg|alert|crit|error)"
    
  • 查看当前连接状态 (非常有用):

    # 需要安装 net-tools
    netstat -an | grep :80 | awk '{print $6}' | sort | uniq -c | sort -rn
    

    这个命令可以统计80端口上各种TCP状态(ESTABLISHED, TIME_WAIT等)的连接数,帮助判断连接池、端口耗尽等问题。

  • 一个常见的502 Bad Gateway错误排查流程

    1. 查Nginx错误日志 ( error.log ): 看是否有 connect() failed (111: Connection refused) upstream timed out 等信息。这指向后端服务不可达或响应超时。
    2. 查后端服务 :确认后端应用(如PHP-FPM, Tomcat)是否在运行,监听端口是否正确。
    3. 查网络连通性 :从Nginx服务器上用 telnet curl 测试是否能连接到后端服务的IP和端口。
    4. 查资源 :检查后端服务器的CPU、内存、磁盘是否已耗尽。
    5. 查配置 :确认Nginx中 proxy_connect_timeout , proxy_read_timeout 等设置是否合理,是否过短。

7. 进阶:使用OpenResty扩展Nginx能力

原生Nginx配置强大,但逻辑能力有限。如果你想在请求处理链中嵌入复杂的业务逻辑(如JWT验证、自定义限流、请求/响应体修改),就需要用到 OpenResty

OpenResty不是Nginx的一个分支,而是一个“打包”,它集成了Nginx核心,并内置了LuaJIT虚拟机,允许你使用Lua脚本直接操作请求的各个阶段。你可以把它理解为“用Lua编程的Nginx”。

一个简单的例子:在访问日志中记录请求处理时间,并实现一个简单的API鉴权。

# 在http块中,加载lua模块并声明共享内存字典(用于缓存等)
http {
    lua_package_path "/usr/local/openresty/lualib/?.lua;;";
    lua_shared_dict my_cache 10m; # 定义一个10MB的共享字典

    server {
        listen 80;
        server_name api.advanced.com;

        # 使用Lua在access阶段记录开始时间
        access_by_lua_block {
            ngx.ctx.start_time = ngx.now() -- 将开始时间存入请求上下文
        }

        location /secure {
            # 在access阶段进行JWT验证
            access_by_lua_file /etc/nginx/lua/jwt_auth.lua;

            # 验证通过后,代理到后端
            proxy_pass http://backend;
        }

        # 在log阶段计算并记录请求耗时
        log_by_lua_block {
            local request_time = ngx.now() - (ngx.ctx.start_time or ngx.req.start_time())
            ngx.log(ngx.INFO, "request_time: ", request_time)
        }
    }
}

/etc/nginx/lua/jwt_auth.lua 文件内容示例:

local jwt = require "resty.jwt"
local auth_header = ngx.var.http_Authorization

if auth_header == nil then
    ngx.status = ngx.HTTP_UNAUTHORIZED
    ngx.say('{"error": "Missing Authorization header"}')
    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

-- 提取Bearer Token
local _, _, token = string.find(auth_header, "Bearer%s+(.+)")
if token == nil then
    ngx.status = ngx.HTTP_UNAUTHORIZED
    ngx.say('{"error": "Invalid token format"}')
    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

-- 验证JWT(这里需要你的密钥)
local secret = "your-secret-key"
local jwt_obj = jwt:verify(secret, token)

if not jwt_obj.verified then
    ngx.status = ngx.HTTP_UNAUTHORIZED
    ngx.say('{"error": "Invalid or expired token"}')
    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end

-- 验证通过,可以将payload中的用户信息传递给后端
ngx.req.set_header("X-User-ID", jwt_obj.payload.sub)

使用OpenResty的心得 :它极大地扩展了Nginx的能力边界,让你能在网关层做非常多的事情,从而减轻后端服务的压力。但引入Lua也增加了复杂性,需要团队具备相应的技能。对于简单的逻辑,优先考虑用Nginx原生指令解决;对于复杂的、需要状态或外部交互的逻辑,OpenResty是绝佳选择。记得充分测试Lua代码的性能,避免在关键路径上执行耗时的操作。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值