本文全面总结企业级高性能Web服务器Nginx的核心知识,包括Apache对比、I/O模型、零拷贝、安装配置、反向代理、负载均衡、FastCGI集成、OpenResty二次开发等,适合运维、开发、架构师学习收藏。


一、Web服务器概述

1.1 Apache 三种工作模式

模式 特点 优缺点
prefork 多进程,每个请求一个进程 稳定但占用内存大,并发差
worker 多进程+多线程 内存占用少,但长连接易阻塞
event 事件驱动(epoll) 高并发表现优秀,解决keepalive阻塞问题

Apache prefork模型:预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024。每个子进程有一个独立的线程响应用户请求,相对比较占用内存,但是比较稳定。优点:稳定;缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差。

Apache worker模型:多进程和多线程混合模型,有一个控制进程启动多个子进程,每个子进程里面包含固定的线程,使用线程来处理请求。优点:相比prefork占用的内存较少,可以同时处理更多的请求;缺点:使用keepalive的长连接方式,某个线程会一直被占据。

Apache event模型:Apache中最新的模式,属于事件驱动模型(epoll),每个进程响应多个请求。它和worker模式很像,最大的区别在于解决了keepalive场景下长期被占用的线程的资源浪费问题。


二、Nginx 高性能Web服务器

2.1 Nginx 特点

  • 解决 C10K 问题(10K Connections)
  • 支持 HTTP/TCP/UDP 代理
  • 模块化设计,高可扩展性
  • 热部署:不停机更新配置文件,升级版本,更换日志文件
  • 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
  • 社区版 + 商业版(Nginx Plus)
  • 天猫、淘宝、京东、小米、163、新浪等一线互联网公司都在用Nginx

2.2 Nginx 进程模型

web请求处理机制

  • 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,处理速度快,子进程之间相互独立,但如果访问过大会导致服务器资源耗尽。
  • 多线程方式:每收到一个客户端请求会有服务进程派生出一个线程进行交互,一个线程的开销远远小于一个进程,但多个线程位于同一个进程内工作,相互影响。

Nginx是多进程组织模型,由Master主进程和Worker工作进程组成:

主进程(master process)的功能

  • 对外接口:接收外部的操作(信号)
  • 对内转发:根据外部的操作的不同,通过信号管理Worker
  • 监控:监控worker进程的运行状态,异常终止后自动重启
  • 读取Nginx配置文件并验证其有效性和正确性
  • 建立、绑定和关闭socket连接
  • 接受外界指令,比如重启、升级及退出服务器等指令
  • 不中断服务,实现平滑升级

工作进程(worker process)的功能

  • 所有Worker进程都是平等的
  • 实际处理网络请求,由Worker进程处理
  • Worker进程数量一般设置为核心数,充分利用CPU资源
  • 接受处理客户的请求
  • I/O调用,获取响应数据
  • 与后端服务器通信,接收后端服务器的处理结果
  • 发送请求结果,响应客户的请求

2.3 常用版本

  • Mainline version:主要开发版本,一般为奇数版本号,比如1.19
  • Stable version:当前最新稳定版,一般为偶数版本,如1.20
  • Legacy versions:旧的稳定版,一般为偶数版本,如1.18

三、I/O模型与Nginx性能

3.1 I/O概念

I/O在计算机中指Input/Output,IOPS(Input/Output Per Second)即每秒的输入输出量,是衡量磁盘性能的主要指标之一。一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换。

服务器的I/O类型

  • 磁盘I/O
  • 网络I/O:一切皆文件,本质为对socket文件的读写

每次I/O都要经由两个阶段

  • 第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
  • 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短

3.2 同步/异步与阻塞/非阻塞

同步/异步:关注的是消息通信机制

  • 同步:被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问
  • 异步:被调用者通过状态、通知或回调机制主动通知调用者

阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态

  • 阻塞:IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起
  • 非阻塞:IO操作被调用后立即返回一个状态值,调用者不会被挂起,可以去做别的事情

3.3 五种I/O模型

模型 说明
阻塞I/O 简单,但进程挂起
非阻塞I/O 轮询,CPU占用高
信号驱动I/O 回调通知,适合少量连接
异步I/O 完美非阻塞,Linux支持不完善
I/O多路复用 Nginx使用,epoll性能最优

阻塞型I/O模型(blocking IO):用户线程在内核进行IO操作时被阻塞,用户需要等待read将数据读取到buffer后,才继续处理。优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用CPU资源。缺点:每个连接需要独立的进程/线程单独处理,并发请求量大时开销较大。

非阻塞型I/O模型(nonblocking IO):用户线程发起IO请求时立即返回,但并未读取到任何数据,需要不断地发起IO请求,直到数据到达。即"轮询"机制,会耗费大量CPU时间,实际使用很少。

信号驱动式I/O模型(signal-driven IO):让内核在数据就绪时,发送信号通知进程。进程通过系统调用sigaction注册一个信号处理的回调函数,该调用会立即返回,主程序可以继续向下执行。优点:线程并没有在等待数据时被阻塞;缺点:信号I/O在大量IO操作时可能会因为信号队列溢出导致没法通知。

异步I/O模型(asynchronous I/O):与信号驱动I/O最大区别在于,信号驱动是内核通知用户进程何时开始一个I/O操作,而异步I/O是由内核通知用户进程I/O操作何时完成。IO两个阶段,进程都是非阻塞的。优点:能够充分利用DMA特性,让I/O操作与计算重叠;缺点:Linux下AIO并不完善,目前在高并发网络编程时以IO复用模型模式+多线程任务的架构基本可以满足需求。

多路复用I/O型(I/O multiplexing):一个线程可以同时监控和处理多个文件描述符对应各自的IO。主要包含select、poll、epoll三种系统调用。

3.4 三种多路复用机制对比

机制 操作方式 最大连接数 效率 fd拷贝
select 遍历 1024(x86) 2048(x64) O(n) 每次调用都需要拷贝
poll 遍历 无上限 O(n) 每次调用都需要拷贝
epoll 回调 无上限 O(1) 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

IO多路复用适用场景

  • 当客户端处理多个描述符时
  • 当一个客户端同时处理多个套接字时
  • 当一个服务器既要处理监听套接字,又要处理已连接套接字
  • 当一个服务器即要处理TCP,又要处理UDP
  • 当一个服务器要处理多个服务或多个协议

四、零拷贝技术

4.1 传统I/O问题

传统的Linux系统的标准I/O接口(read、write)是基于数据拷贝的,数据都是copy_to_user或者copy_from_user。大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的CPU资源。在Linux协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整个处理流程时间的57.1%。

4.2 零拷贝方案

零拷贝通过尽量避免拷贝操作来缓解CPU的压力,并没有真正做到"0"拷贝,更多是一种思想。

MMAP(Memory Mapping)
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。

内存映射的优势:减少数据在用户空间和内核空间之间的拷贝操作,适合大量数据传输。mmap要比普通的read系统调用少了一次copy的过程,因为进程可以直接访问mmap的数据(pagecache)。


五、Nginx 安装与配置

5.1 编译安装示例

# 安装依赖
dnf install gcc pcre-devel zlib-devel openssl-devel -y

创建运行用户

useradd -s /sbin/nologin -M nginx

解压并编译

tar zxf nginx-1.24.0.tar.gz
cd nginx-1.24.0/

./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module

make && make install

5.2 核心目录结构
目录 说明

conf/	保存nginx所有的配置文件,nginx.conf是核心配置文件
html/	保存nginx服务器的web文件
logs/	保存nginx服务器的访问日志错误日志等
sbin/	保存nginx二进制启动脚本
5.3 Nginx命令常用选项
bash
nginx -v          # 显示版本
nginx -V          # 显示版本和编译参数
nginx -t          # 测试配置文件是否正确
nginx -T          # 测试并打印配置
nginx -s signal   # 发送信号:stop, quit, reopen, reload
nginx -c filename # 指定配置文件路径

5.4 systemd启动文件配置

bash
vim /lib/systemd/system/nginx.service
ini
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

5.5 平滑升级与回滚
平滑升级流程:

将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)

向master进程发送USR2信号

master进程修改pid文件加上后缀.oldbin

master进程用新Nginx文件启动新master进程成为旧master的子进程

向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止

向旧master进程发送QUIT信号,关闭老master

如果发现升级有问题,可以回滚:向老master发送HUP,向新master发送QUIT

六、Nginx 核心配置详解
6.1 配置结构
text
main block(主配置段,全局生效)
├── events(事件驱动相关配置)
├── http(HTTP/HTTPS协议相关配置)
│ ├── server(虚拟主机配置)
│ │ ├── location(URL匹配配置)
│ ├── upstream(后端服务器分组)
├── mail(邮件协议相关配置)
├── stream(TCP/UDP代理相关配置)
6.2 全局配置常用指令

nginx
user nginx nginx;                    # 启动Nginx工作进程的用户和组
worker_processes auto;               # 工作进程数量,一般设为CPU核心数
worker_cpu_affinity auto;            # 绑定CPU核心
error_log logs/error.log error;      # 错误日志配置
pid logs/nginx.pid;                  # PID文件保存路径
worker_priority 0;                   # 工作进程优先级
worker_rlimit_nofile 65536;          # 所有worker进程能打开的文件数量上限

events {
    worker_connections 1024;         # 单个worker进程最大并发连接数
    use epoll;                        # 使用epoll事件驱动模型
    accept_mutex on;                  # 工作进程可以同时接受多个新连接
    multi_accept on;                  # 每个工作进程可以同时接受多个新网络连接
}

6.3 http配置块常用指令

nginx
include mime.types;                  # MIME类型映射
default_type application/octet-stream; # 默认MIME类型
sendfile on;                         # 启用sendfile,零拷贝
keepalive_timeout 65;                # 长连接超时时间
keepalive_requests 100;              # 一次长连接允许请求的最大资源数量

6.4 location 匹配规则
符号 说明 优先级
= 精确匹配 最高
^~ 匹配URI开始 高
~ 区分大小写正则匹配 中
~* 不区分大小写正则匹配 中
无符号 前缀匹配 低
匹配优先级:= > ^~ > ~ / ~* > 完整路径 > 部分起始路径 > /

6.5 root与alias的区别
nginx

root:给定的路径对应于location中的/uri左侧的/

location /dirtest {
    root /mnt;           # 实际路径:/mnt/dirtest
}

alias:给定的路径对应于location中的/uri的完整路径

location /alias {
    alias /mnt/dirtest;  # 实际路径:/mnt/dirtest(注意about后不要加/)
}

6.6 常见功能配置示例

用户认证:

nginx
location /login {
    auth_basic "login password";
    auth_basic_user_file "/usr/local/nginx/conf/.htpasswd";
}
自定义错误页面:

nginx
error_page 404 /40x.html;
location = /40x.html {
    root /webdata/nginx/errors;
}
下载服务器:

nginx
location /download {
    autoindex on;                    # 自动索引功能
    autoindex_exact_size off;        # 显示大概大小(K/M)
    autoindex_localtime on;          # 显示本机时间
    limit_rate 4k;                   # 限制传输速率
}
try_files检测文件是否存在:

nginx
try_files $uri $uri.html $uri/index.html /error/default.html;

七、Nginx 高级功能
7.1 状态页
需要编译参数–with-http_stub_status_module支持:

nginx
location /nginx_status {
    stub_status;
    auth_basic "auth login";
    auth_basic_user_file /apps/nginx/conf/.htpasswd;
    allow 192.168.0.0/16;
    allow 127.0.0.1;
    deny all;
}
状态页输出信息说明:

Active connections:当前处于活动状态的客户端连接数

accepts:Nginx自启动后已经接受的客户端请求连接的总数

handled:Nginx自启动后已经处理完成的客户端请求连接总数

requests:Nginx自启动后客户端发来的总请求数

Reading:正在读取客户端请求报文首部的连接数

Writing:正在向客户端发送响应报文过程中的连接数

Waiting:正在等待客户端发出请求的空闲连接数

7.2 压缩功能
依赖模块ngx_http_gzip_module(默认内置):

nginx
gzip on;                           # 启用gzip压缩
gzip_comp_level 5;                 # 压缩比1-9,默认为1
gzip_min_length 1k;                # 最小压缩文件大小
gzip_disable "MSIE [1-6]\.";       # 禁用IE6压缩
gzip_types text/plain text/css application/json application/javascript;
gzip_vary on;                      # 响应报文首部插入"Vary: Accept-Encoding"
7.3 版本隐藏
bash

编辑源码文件

vim src/core/nginx.h

#define NGINX_VERSION "1.0"
#define NGINX_VER "HAHA/" NGINX_VERSION
7.4 内置变量
变量	说明
$remote_addr	客户端地址(公网IP)
$args	URL中的所有参数
$document_root	当前请求的系统根目录
$document_uri	当前请求中不包含参数的URI
$host	请求的host名称
$request_method	请求方式(GET/POST等)
$request_uri	包含请求参数的原始URI
$scheme	请求协议(http/https)
$server_addr	服务器IP地址
$server_name	虚拟主机名
$server_port	虚拟主机端口号
$http_user_agent	客户端浏览器详细信息
$http_cookie	客户端的所有cookie信息
7.5 自定义变量
nginx
set $variable value;   # 语法格式
set $name timinglee;   # 示例
7.6 Rewrite功能
if指令:

nginx
if ($scheme = http) {
    rewrite / https://$host redirect;
}

if (!-e $request_filename) {
    return 404;
}
return指令:

nginx
return code;                    # 返回状态码
return code [text];             # 返回状态码及提示文本
return code URL;                # 重定向到URL
break指令:中断当前相同作用域中的其他Nginx配置

rewrite指令:

nginx
rewrite regex replacement [flag];
flag说明:

flag	说明	状态码
redirect	临时重定向	302
permanent	永久重定向	301
break	停止重写,跳转至其他配置	-
last	停止重写,启动新一轮重写检查	-
7.7 防盗链配置
nginx
location / {
    valid_referers none blocked server_names *.timinglee.org ~\.baidu\.;
    if ($invalid_referer) {
        return 403;
    }
}
referer类型说明:

none:请求报文首部没有referer

blocked:有referer但无有效值

server_names:referer包含本主机名

八、反向代理与负载均衡
8.1 HTTP 反向代理配置参数

nginx
proxy_pass http://backend;                 # 转发请求到后端服务器
proxy_hide_header ETag;                    # 隐藏响应头部信息
proxy_pass_header Server;                  # 透传后端服务器头部信息
proxy_set_header Host $host;               # 设置请求头部
proxy_set_header X-Forwarded-For $remote_addr;  # 传递客户端真实IP
proxy_connect_timeout 60s;                 # 连接超时时间
proxy_read_timeout 60s;                    # 读取超时时间
proxy_send_timeout 60s;                    # 发送超时时间
8.2 负载均衡 upstream配置
nginx
upstream webserver {
    server 192.168.1.10:80 weight=3 max_fails=3 fail_timeout=30s;
    server 192.168.1.20:80 weight=1;
    server 192.168.1.30:80 backup;
    server 192.168.1.40:80 down;
}
server参数说明:

参数	说明
weight=number	权重,默认为1
max_conns=number	最大活动连接数
max_fails=number	下线检测失败次数
fail_timeout=time	上线检测间隔时间
backup	备用服务器
down	标记为下线状态
8.3 调度算法
算法	说明
round-robin	轮询(默认)
least_conn	最少连接数
ip_hash	源地址hash,实现会话保持
hash key [consistent]	基于key的hash,consistent表示一致性hash
8.4 缓存配置
nginx

在http块中定义缓存

proxy_cache_path /var/cache/nginx/proxy_cache 
    levels=1:2:2 
    keys_zone=proxycache:20m 
    inactive=120s 
    max_size=10g;

在location中使用缓存

location ~ /static {
    proxy_pass http://backend;
    proxy_cache proxycache;
    proxy_cache_key $request_uri;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid any 1m;
    proxy_cache_use_stale error http_502 http_503;
}

九、四层负载均衡(TCP/UDP)
需要编译参数–with-stream支持:

9.1 TCP负载均衡(MySQL示例)

nginx
stream {
    upstream mysql_server {
        server 192.168.1.20:3306 max_fails=3 fail_timeout=30s;
        server 192.168.1.30:3306 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 3306;
        proxy_pass mysql_server;
        proxy_connect_timeout 30s;
        proxy_timeout 300s;
    }
}

9.2 UDP负载均衡(DNS示例)

nginx
stream {
    upstream dns_server {
        server 192.168.1.20:53 max_fails=3 fail_timeout=30s;
        server 192.168.1.30:53 max_fails=3 fail_timeout=30s;
    }
    server {
        listen 53 udp;
        proxy_pass dns_server;
        proxy_timeout 1s;
        proxy_responses 1;        # UDP协议期望的数据报文数
    }
}

十、FastCGI 与 PHP 集成
10.1 FastCGI配置参数

nginx
fastcgi_pass address:port;           # 转发到后端FastCGI服务器
fastcgi_index index.php;             # 默认主页资源
fastcgi_param REMOTE_ADDR $remote_addr;  # 传递参数
10.2 源码编译PHP
bash

安装依赖

dnf install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel libcurl-devel oniguruma-devel

编译配置

./configure --prefix=/usr/local/php \
--enable-fpm \
--with-fpm-user=nginx \
--with-fpm-group=nginx \
--with-curl \
--with-openssl \
--enable-mysqlnd \
--with-pdo-mysql \
--enable-sockets \
--enable-soap \
--enable-gd \
--enable-mbstring

make && make install
10.3 PHP-FPM配置
bash
cp php-fpm.conf.default php-fpm.conf
cp php-fpm.d/www.conf.default php-fpm.d/www.conf

修改www.conf

listen = 0.0.0.0:9000

修改php.ini

date.timezone = Asia/Shanghai
10.4 Nginx配置PHP转发
nginx
server {
    listen 80;
    server_name php.timinglee.org;
    root /data/php;
    
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

十一、PHP缓存加速

11.1 安装memcache模块
bash
tar zxf memcache-8.2.tgz
cd memcache-8.2/
phpize
./configure && make && make install

修改php.ini

extension=memcache
11.2 部署memcached
bash
yum install memcached -y
systemctl enable --now memcached
11.3 Nginx整合memc缓存
需要第三方模块:srcache-nginx-module和memc-nginx-module

nginx
upstream memcache {
    server 127.0.0.1:11211;
    keepalive 512;
}

server {
    listen 80;
    server_name php.timinglee.org;
    root /data/php;
    
    location /memc {
        internal;
        memc_connect_timeout 100ms;
        set $memc_key $query_string;
        set $memc_exptime 300;
        memc_pass memcache;
    }
    
    location ~ \.php$ {
        set $key $uri$args;
        srcache_fetch GET /memc $key;
        srcache_store PUT /memc $key;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

十二、OpenResty二次开发
OpenResty是基于Nginx与Lua的高性能Web平台,由中国人章亦春开发,内部集成了大量精良的Lua库和第三方模块。

12.1 编译安装OpenResty

dnf -y install gcc pcre-devel openssl-devel perl
useradd -r -s /sbin/nologin nginx

tar xf openresty-1.17.8.2.tar.gz
cd openresty-1.17.8.2/

./configure --prefix=/apps/openresty \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module

make && make install
ln -s /apps/openresty/bin/* /usr/bin/

十三、总结与建议
场景 推荐方案
静态文件服务 Nginx + sendfile + gzip
高并发Web Nginx + epoll + 多Worker
动态PHP Nginx + PHP-FPM + FastCGI
反向代理 Nginx + upstream + 缓存
会话保持 ip_hash / hash cookie
四层代理 Nginx stream模块
二次开发 OpenResty + Lua
生产环境建议:

使用稳定版Nginx(偶数版本)

编译安装可定制模块,性能更优

工作进程数设置为CPU核心数

使用nginx -t检查配置正确性

使用systemd管理Nginx服务

开启gzip压缩优化传输效率

配置合适的缓存策略

使用HTTPS时开启SSL会话缓存

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐