浅谈Nginx

🔍 1. 什么是 Nginx?

详细解析:

Nginx(发音为"engine-x")是一个高性能的开源 Web 服务器 ,同时也作为反向代理服务器负载均衡器HTTP 缓存使用。

核心特性:

  • 事件驱动架构:采用异步非阻塞 I/O 模型,能够高效处理大量并发连接

  • 模块化设计:通过模块扩展功能,支持自定义开发

  • 低内存消耗:特别是在处理静态文件时表现优异

  • 高稳定性:能够长时间运行而不需要重启

支持的协议:

  • HTTP/1.0、HTTP/1.1、HTTP/2

  • HTTPS(SSL/TLS)

  • SMTP、POP3、IMAP(作为邮件代理)

  • WebSocket

  • gRPC

应用场景:

  • 静态内容服务

  • 动态内容反向代理

  • API 网关

  • 负载均衡

  • 内容缓存

  • SSL 终端


🧩 2. Nginx 的特性

详细解析:

2.1 反向代理 / L7 负载均衡器

bash 复制代码
upstream backend {
    server 10.0.0.1:8080 weight=3;
    server 10.0.0.2:8080 weight=2;
    server 10.0.0.3:8080 backup;
}

server {
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

负载均衡算法:

  • 轮询(默认)

  • 最少连接(least_conn)

  • IP 哈希(ip_hash)

  • 加权轮询

2.2 嵌入式 Perl 解释器

  • 允许在配置文件中嵌入 Perl 代码

  • 支持复杂的请求处理逻辑

  • 逐渐被 Lua 模块(OpenResty)替代

2.3 动态二进制升级

bash

复制代码
# 无需停止服务即可升级
nginx -s upgrade

优势:

  • 零停机时间更新

  • 保持现有连接不中断

  • 回滚机制

2.4 URL 重写与 PCRE 支持

bash 复制代码
location /products {
    rewrite ^/products/(.*)$ /items/$1 permanent;
}

location ~* \.(jpg|jpeg|png|gif)$ {
    expires 30d;
    add_header Cache-Control "public";
}

⚖️ 3. Nginx 与 Apache 的不同点

详细对比:

特性 Nginx Apache
架构模型 事件驱动、异步非阻塞 多进程/多线程、同步阻塞
并发处理 单进程可处理数万并发 受限于进程/线程数量
内存使用 较低且稳定 随并发数线性增长
静态内容 性能极高 性能一般
动态内容 需转发给后端处理器 内置模块支持(如 mod_php)
配置方式 集中式配置,不支持 .htaccess 支持分布式 .htaccess
热部署 支持 有限支持
学习曲线 较陡峭 相对平缓

选择建议:

  • 选择 Nginx:高并发、静态内容多、内存受限

  • 选择 Apache:需要 .htaccess、共享主机环境、传统应用


🔁 4. Nginx 如何处理 HTTP 请求?

详细架构解析:

4.1 事件驱动模型

c

bash 复制代码
// 伪代码表示事件循环
while (true) {
    events = epoll_wait(epoll_fd, events_list, MAX_EVENTS, -1);
    for (i = 0; i < events; i++) {
        if (events_list[i].events & EPOLLIN) {
            // 处理读事件
            handle_read_event(events_list[i].data.fd);
        }
        if (events_list[i].events & EPOLLOUT) {
            // 处理写事件
            handle_write_event(events_list[i].data.fd);
        }
    }
}

4.2 请求处理流程

  1. 接收连接:Worker 进程接受新连接

  2. 解析请求:解析 HTTP 头部,确定虚拟主机

  3. 匹配 Location:根据 URI 匹配 location 块

  4. 处理请求:执行相应的处理逻辑(静态文件、代理等)

  5. 生成响应:构建 HTTP 响应

  6. 发送响应:异步发送响应数据

4.3 多进程架构

bash 复制代码
Master Process (PID: 1001)
├── Worker Process (PID: 1002) → 处理连接 A、C、E...
├── Worker Process (PID: 1003) → 处理连接 B、D、F...
└── Cache Manager/Loader (PID: 1004)

🚫 5. 如何使用未定义的服务器名称阻止请求?

详细配置说明:

bash 复制代码
# 方法1:使用空服务器名
server {
    listen 80;
    server_name "";
    return 444;  # Nginx 自定义状态码,关闭连接
}

# 方法2:默认服务器捕获所有未匹配请求
server {
    listen 80 default_server;
    server_name _;
    deny all;
    return 444;
}

# 方法3:针对特定非法域名
server {
    listen 80;
    server_name malicious.com *.hacker.org;
    access_log off;
    error_log off;
    return 444;
}

应用场景:

  • 防止域名恶意指向

  • 阻止扫描器探测

  • 减少无效请求的资源消耗


🛡️ 6. 反向代理服务器的优点

详细优势分析:

6.1 安全性增强

bash 复制代码
# 隐藏后端服务器信息
proxy_pass http://backend;
proxy_hide_header X-Powered-By;
proxy_hide_header Server;

# 添加安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

6.2 负载均衡

bash 复制代码
upstream app_servers {
    zone backend 64k;
    least_conn;
    
    server 10.1.1.1:8080 max_fails=3 fail_timeout=30s;
    server 10.1.1.2:8080 max_fails=3 fail_timeout=30s;
    server 10.1.1.3:8080 max_fails=3 fail_timeout=30s backup;
}

6.3 内容缓存

bash 复制代码
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;

location / {
    proxy_cache my_cache;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;
    proxy_pass http://backend;
}

6.4 SSL 终端

bash 复制代码
server {
    listen 443 ssl;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    location / {
        proxy_pass http://backend;  # 后端使用 HTTP
    }
}

🚀 7. Nginx 的最佳用途

详细应用场景:

7.1 静态内容服务

bash 复制代码
server {
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
    
    location /static/ {
        alias /var/www/static/;
        autoindex off;
    }
}

7.2 动态内容代理

bash 复制代码
# Spring Boot 应用 (内嵌 Tomcat/Jetty)
location /spring-boot/ {
    # 代理到 Spring Boot 应用
    proxy_pass http://127.0.0.1:8080/;
    
    # 代理头设置
    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;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    
    # 超时设置
    proxy_connect_timeout 30s;
    proxy_send_timeout 30s;
    proxy_read_timeout 30s;
    
    # 缓冲设置
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
    
    # 启用 WebSocket 支持
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

# Spring Boot Actuator 端点
location /spring-boot/actuator/ {
    proxy_pass http://127.0.0.1:8080/actuator/;
    proxy_set_header Host $host;
    
    # 安全限制
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;
    
    access_log off;
}

7.3 负载均衡器

bash 复制代码
upstream microservices {
    zone upstreams 64k;
    
    server api1.example.com:8080 weight=2;
    server api2.example.com:8081;
    server api3.example.com:8082 backup;
    
    # 健康检查
    health_check interval=5s fails=3 passes=2;
}

👨‍💼 8. Master 和 Worker 进程

详细进程架构:

8.1 Master 进程职责

bash 复制代码
# 查看进程树
$ pstree -p | grep nginx
nginx(1001)─┬─nginx(1002)
            ├─nginx(1003)
            ├─nginx(1004)
            └─nginx(1005)

Master 进程功能:

  • 读取和验证配置文件

  • 绑定监听端口

  • 管理 Worker 进程(启动、停止、重启)

  • 平滑升级二进制文件

  • 重新打开日志文件

8.2 Worker 进程职责

bash 复制代码
# 配置 Worker 进程
worker_processes auto;  # CPU 核心数
worker_cpu_affinity auto;
worker_rlimit_nofile 100000;  # 文件描述符限制

events {
    worker_connections 10240;  # 每个 Worker 最大连接数
    use epoll;  # 事件模型
    multi_accept on;
}

Worker 进程特性:

  • 独立的进程,互不影响

  • 处理实际的网络连接

  • 使用异步非阻塞 I/O

  • 可配置的 CPU 亲和性


🔧 9. 如何在非 80 端口启动 Nginx?

详细配置方法:

9.1 修改默认配置文件

bash 复制代码
# /etc/nginx/sites-available/default
server {
    listen 8080;  # 改为 8080 端口
    listen [::]:8080;
    
    server_name example.com;
    root /var/www/html;
    
    index index.html index.htm;
}

9.2 多端口监听

bash 复制代码
server {
    listen 80;
    listen 443 ssl;
    listen 8080;
    listen 8443 ssl;
    
    server_name example.com;
    # ... 其他配置
}

9.3 SELinux 环境下的注意事项

bash 复制代码
# 检查当前端口上下文
semanage port -l | grep http

# 添加新端口
semanage port -a -t http_port_t -p tcp 8080

# 重启 Nginx
systemctl restart nginx

9.4 防火墙配置

bash 复制代码
# 开放端口
ufw allow 8080/tcp
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

❗ 10. 替换错误为 502/503

详细错误处理配置:

10.1 基本错误页面配置

bash 复制代码
http {
    # 定义错误页面
    error_page 500 502 503 504 /50x.html;
    error_page 404 /404.html;
    
    location = /50x.html {
        root /usr/share/nginx/html;
        internal;
    }
    
    location = /404.html {
        root /usr/share/nginx/html;
        internal;
    }
}

10.2 动态错误处理

bash 复制代码
location /api/ {
    proxy_pass http://backend;
    proxy_intercept_errors on;
    
    # 将 502 错误转换为 503
    error_page 502 =503 /maintenance.html;
    
    # 自定义错误处理
    error_page 404 = @fallback;
    error_page 500 502 503 504 = @down;
}

location @fallback {
    try_files $uri $uri/ @proxy;
}

location @down {
    add_header Retry-After 3600;
    return 503 "Service temporarily unavailable";
}

10.3 FastCGI 错误拦截

bash 复制代码
location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php-fpm.sock;
    fastcgi_intercept_errors on;
    
    # 拦截 FastCGI 错误
    error_page 500 502 503 504 /error.php;
    
    include fastcgi_params;
}

🔗 11. 保留 URL 中的双斜线

详细配置说明:

11.1 merge_slashes 指令

bash 复制代码
server {
    # 关闭斜线合并
    merge_slashes off;
    
    location /api/ {
        # 某些路径允许双斜线
        merge_slashes off;
        proxy_pass http://backend;
    }
    
    location /static/ {
        # 静态资源通常不需要双斜线
        merge_slashes on;
        try_files $uri $uri/ =404;
    }
}

11.2 应用场景

  • API 路径/api/v1//users 可能需要保留双斜线

  • 文件路径//share//file.txt 特殊文件系统

  • URL 重写:保留原始 URL 结构

11.3 正则表达式处理

bash 复制代码
location ~* "^//+(.*)$" {
    # 处理多个斜线开头的请求
    rewrite "^//+(.*)$" /$1 break;
    proxy_pass http://backend;
}

🔁 12. ngx_http_upstream_module 的作用

详细模块功能:

12.1 上游服务器定义

bash 复制代码
upstream backend {
    # 基础配置
    server 10.0.1.1:8080;
    server 10.0.1.2:8080;
    
    # 负载均衡方法
    least_conn;  # 最少连接
    
    # 健康检查
    health_check interval=5s fails=3 passes=2;
}

12.2 服务器参数详解

bash 复制代码
upstream app_servers {
    # 服务器状态
    server 10.0.1.1:8080 weight=5;    # 主服务器,权重高
    server 10.0.1.2:8080 weight=3;    # 次要服务器
    server 10.0.1.3:8080 down;        # 停机维护
    server 10.0.1.4:8080 backup;      # 备份服务器
    
    # 故障转移设置
    server 10.0.1.5:8080 max_fails=3 fail_timeout=30s;
    
    # 解析器用于动态 DNS
    resolver 8.8.8.8 valid=30s;
}

12.3 代理配置

bash 复制代码
location / {
    proxy_pass http://backend;
    
    # 超时设置
    proxy_connect_timeout 5s;
    proxy_send_timeout 10s;
    proxy_read_timeout 30s;
    
    # 缓冲设置
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
    
    # 重试机制
    proxy_next_upstream error timeout invalid_header;
    proxy_next_upstream_tries 3;
    proxy_next_upstream_timeout 30s;
}

💥 13. 什么是 C10K 问题?

详细技术解析:

13.1 问题定义

C10K(Concurrent 10,000 Connections)指的是服务器同时处理一万个并发连接的技术挑战。

13.2 传统服务器的限制

c

bash 复制代码
// 传统阻塞 I/O 模型
while (1) {
    client_fd = accept(server_fd);  // 阻塞
    read(client_fd, buffer);        // 阻塞
    process_request(buffer);
    write(client_fd, response);     // 阻塞
    close(client_fd);
}

13.3 Nginx 的解决方案

c

bash 复制代码
// 事件驱动模型
while (1) {
    n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
    for (i = 0; i < n; i++) {
        if (events[i].data.fd == server_fd) {
            // 接受新连接
            client_fd = accept(server_fd);
            set_nonblocking(client_fd);
            add_to_epoll(client_fd);
        } else {
            // 处理现有连接
            handle_client(events[i].data.fd);
        }
    }
}

13.4 现代解决方案

  • I/O 多路复用:epoll(Linux)、kqueue(BSD)

  • 异步 I/O:io_uring(Linux)

  • 用户态网络栈 :DPDK、FD.io


📊 14. stub_status 和 sub_filter 指令

详细功能说明:

14.1 stub_status 指令

bash 复制代码
# 启用状态页面
server {
    listen 80;
    server_name status.example.com;
    
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 192.168.1.0/24;
        deny all;
    }
}

状态信息解读:

bash 复制代码
Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
  • Active connections:当前活跃连接数

  • accepts:接受的客户端连接总数

  • handled:处理的连接数

  • requests:客户端请求总数

  • Reading:正在读取请求头的连接数

  • Writing:正在写入响应的连接数

  • Waiting:空闲客户端连接数

14.2 sub_filter 指令

bash 复制代码
location / {
    proxy_pass http://backend;
    
    # 内容替换
    sub_filter 'http://old-domain.com' 'https://new-domain.com';
    sub_filter 'Old Text' 'New Text';
    sub_filter_once off;  # 替换所有出现
    sub_filter_types text/html text/css;  # 指定 MIME 类型
    
    # 响应头修改
    sub_filter_last_modified on;
}

应用场景:

  • 域名迁移

  • 内容更新

  • A/B 测试

  • 错误修复


🗜️ 15. 是否支持将请求压缩到上游?

详细压缩配置:

15.1 响应解压缩(gunzip)

bash 复制代码
# 启用解压缩模块
http {
    gunzip on;
    gunzip_buffers 16 8k;
    
    location / {
        proxy_pass http://backend;
        
        # 如果后端返回压缩内容,但客户端不支持
        gunzip on;
    }
}

15.2 请求压缩

bash 复制代码
# 向上游发送压缩请求
location /api/ {
    proxy_pass http://backend;
    
    # 启用请求体压缩
    proxy_set_header Accept-Encoding "gzip";
    
    # 压缩请求体(需要相应模块)
    client_body_in_file_only clean;
    client_body_buffer_size 128K;
}

15.3 响应压缩(gzip)

bash 复制代码
http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;
    
    # 预压缩文件支持
    gzip_static on;
}

⏰ 16. 如何在 Nginx 中获得当前的时间?

详细时间变量:

16.1 内置时间变量

bash 复制代码
server {
    location /time {
        # 返回当前时间
        add_header Content-Type "text/plain";
        return 200 "GMT: $date_gmt\nLocal: $date_local\n";
    }
    
    location /api/ {
        proxy_pass http://backend;
        
        # 传递时间戳给后端
        proxy_set_header X-Request-Time $msec;
        proxy_set_header X-Request-Date $date_gmt;
    }
}

16.2 可用时间变量

  • $date_gmt:GMT 格式的当前时间

  • $date_local:本地时区格式的当前时间

  • $time_iso8601:ISO 8601 格式时间

  • $time_local:本地时间的通用日志格式

  • $msec:带毫秒的 Unix 时间戳

16.3 SSI 模块时间显示

bash 复制代码
location /ssi-page {
    ssi on;
    
    # 在 HTML 中嵌入时间
    # <!--# echo var="date_gmt" -->
    # <!--# config timefmt="%Y-%m-%d %H:%M:%S" -->
}

⚙️ 17. Nginx -s 参数的作用

详细信号管理:

17.1 常用信号命令

bash 复制代码
# 重新加载配置(平滑重启)
nginx -s reload

# 立即停止
nginx -s stop

# 优雅停止(处理完当前请求)
nginx -s quit

# 重新打开日志文件(用于日志轮转)
nginx -s reopen

17.2 信号对应关系

bash 复制代码
# 直接向进程发送信号
kill -HUP $(cat /var/run/nginx.pid)    # 等同于 reload
kill -QUIT $(cat /var/run/nginx.pid)   # 等同于 quit
kill -TERM $(cat /var/run/nginx.pid)   # 等同于 stop
kill -USR1 $(cat /var/run/nginx.pid)   # 等同于 reopen

17.3 信号处理流程

bash 复制代码
用户命令: nginx -s reload
    ↓
发送 HUP 信号给 Master 进程
    ↓
Master 检查新配置语法
    ↓
启动新的 Worker 进程
    ↓
优雅关闭旧的 Worker 进程
    ↓
完成平滑重启

🧩 18. 如何在 Nginx 中添加模块?

详细模块管理:

18.1 编译时添加模块

bash 复制代码
# 查看当前已编译模块
nginx -V

# 下载 Nginx 源码
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxvf nginx-1.24.0.tar.gz
cd nginx-1.24.0

# 配置编译参数(包含现有模块和新模块)
./configure \
    --prefix=/etc/nginx \
    --sbin-path=/usr/sbin/nginx \
    --modules-path=/usr/lib/nginx/modules \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_stub_status_module \
    --add-module=/path/to/custom-module \
    --add-dynamic-module=/path/to/dynamic-module

# 编译和安装
make
make install

18.2 动态模块加载

bash 复制代码
# 在 nginx.conf 中加载动态模块
load_module modules/ngx_http_geoip_module.so;
load_module modules/ngx_stream_geoip_module.so;

http {
    # 使用动态模块
    geoip_country /usr/share/GeoIP/GeoIP.dat;
}

18.3 常用第三方模块

  • OpenResty:LuaJIT 支持

  • Headers More:增强的头部控制

  • Cache Purge:缓存清理

  • Fancy Index:美观的目录列表

18.4 模块开发基础

c

bash 复制代码
// 简单的 Hello World 模块
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
    ngx_str_t response = ngx_string("Hello, Nginx Module!");
    
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;
    
    ngx_http_send_header(r);
    return ngx_http_output_filter(r, &response);
}
相关推荐
乘云数字DATABUFF2 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--4 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森4 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜5 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB6 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode7 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220708 天前
如何搭建本地yum源(上)
运维
ping某9 天前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
大树8811 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠11 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql