1.1 web 服务器到底做什么
当你在浏览器输入一个网址,背后发生的事情是:浏览器与服务器建立 TCP 连接,发出一条 HTTP 请求(比如 GET /index.html),服务器读取请求、找到对应资源、返回一条 HTTP 响应。承担"接收请求、返回响应"这个角色的程序,就是 web 服务器。
web 服务器的活儿主要有三类:发静态文件(HTML/CSS/JS/图片)、把动态请求转交给后端应用(PHP/Node/Java 进程)、以及处理网络层的杂事(TLS 加密、压缩、缓存、限流)。Nginx 三样都擅长。
- web 服务器(Web Server)
- 接收 HTTP 请求、返回响应的程序。狭义指发静态文件的服务器(Nginx、Apache),广义也包含应用服务器。
- 反向代理(Reverse Proxy)
- 代替后端服务器接收客户端请求,再转发给内网真正处理请求的应用,把响应带回客户端。客户端并不知道背后有几台机器。
- 正向代理(Forward Proxy)
- 代替客户端去访问外部服务器(如公司出口代理、科学上网)。方向与反向代理相反:一个代理"客户端",一个代理"服务端"。
- C10K 问题
- 指单台服务器同时处理 1 万(10K)并发连接的挑战。传统"一连接一线程"模型在此规模下因内存和上下文切换而崩溃,催生了 Nginx 的事件驱动设计。
- 阻塞 I/O(Blocking I/O)
- 线程发起读写后一直卡住等待结果,期间什么也干不了。连接多时需要大量线程,每个线程都在"傻等"。
- 事件驱动(Event-driven)
- 用一个事件循环监听大量连接的"可读/可写"事件,哪个就绪就处理哪个,单线程即可复用成千上万连接,不为每个连接开线程。
1.2 Nginx vs Apache:两种并发哲学
Apache(尤其经典的 prefork/worker MPM)的模型是每个连接分配一个进程或线程。这个模型直观、稳定,但代价高:1 万并发就要 1 万个线程,每个线程占几 MB 栈内存,光内存就是几十 GB,CPU 大量时间耗在线程切换上。
Nginx 的模型是少量 worker 进程 + 事件循环。一个 worker 通过 epoll(Linux)/kqueue(BSD/macOS)同时管理上万连接,只在连接真正"有数据可处理"时才去处理它,其余时间不占用线程。这就是它能用极少内存扛住 C10K 甚至 C1M 的秘密。
| 维度 | Nginx | Apache(prefork) |
|---|---|---|
| 并发模型 | 事件驱动 / 异步非阻塞 | 每连接一进程/线程 |
| 高并发内存 | 极低(连接≈几 KB) | 高(线程≈几 MB) |
| 静态文件性能 | 极强(sendfile 零拷贝) | 中等 |
| 动态内容 | 需反代给 PHP-FPM/应用 | 可内嵌 mod_php |
| 配置方式 | 集中式 nginx.conf | .htaccess 分布式 + 主配置 |
| 典型角色 | 反代/均衡/静态/TLS 终止 | 传统 LAMP 应用服务器 |
现实中常见组合是 Nginx 在最前面做反向代理、负载均衡、静态资源和 TLS 终止,把动态请求转发给后面的应用服务器(可能就是 Apache + PHP,或 Node、Java 等)。二者并非你死我活。
1.3 master-worker 架构
Nginx 启动后不是一个进程,而是一组:一个 master 进程 + 若干 worker 进程。
- master 进程
- 以 root 启动,负责读取配置、绑定端口、管理 worker 生命周期、响应信号(重载/退出)。它不处理任何客户端请求。
- worker 进程
- 真正干活的进程,通常降权到普通用户运行。每个 worker 独立跑一个事件循环,处理连接。数量一般设为 CPU 核心数。
- cache manager / cache loader
- 可选的辅助进程,负责管理磁盘缓存(proxy_cache)的过期清理与启动时加载。
# 看看 Nginx 的进程树
$ ps aux | grep nginx
root 1200 nginx: master process /usr/sbin/nginx
www-data 1201 nginx: worker process
www-data 1202 nginx: worker process
www-data 1203 nginx: worker process
www-data 1204 nginx: worker process
这种设计的好处:master 用 root 权限绑定 80/443 端口后,worker 降权运行更安全;重载配置时 master 可以优雅地启动新 worker、让旧 worker 处理完手头请求再退出,实现零停机重载(第 2 章详解)。
1.4 安装 Nginx
# Ubuntu / Debian
$ sudo apt update
$ sudo apt install nginx
# CentOS / RHEL / Rocky
$ sudo dnf install nginx
# macOS(Homebrew)
$ brew install nginx
# 验证版本与编译参数
$ nginx -v
nginx version: nginx/1.27.0
$ nginx -V # 大写 V 显示编译时的模块
Nginx 有两条线:stable(偶数小版本,如 1.26.x)只修 bug,适合生产;mainline(奇数,如 1.27.x)含新特性。官方其实推荐大多数场景用 mainline。发行版仓库通常给的是较旧的 stable,需要新特性可加官方源。
1.5 启停与常用命令
# 用 systemd 管理(发行版安装的推荐方式)
$ sudo systemctl start nginx # 启动
$ sudo systemctl stop nginx # 停止
$ sudo systemctl restart nginx # 重启(会短暂中断)
$ sudo systemctl reload nginx # 平滑重载配置(不中断连接)
$ sudo systemctl enable nginx # 开机自启
$ sudo systemctl status nginx # 查看状态
# 用 nginx 命令直接控制
$ sudo nginx # 启动
$ sudo nginx -s reload # 重载配置
$ sudo nginx -s stop # 立即停止
$ sudo nginx -s quit # 优雅停止(处理完当前请求)
$ sudo nginx -t # 检查配置语法是否正确
养成肌肉记忆:任何配置改动后,先跑 nginx -t 验证语法,通过了再 reload。直接 reload 一个语法错误的配置,Nginx 会拒绝加载并沿用旧配置——虽然不会挂,但你的改动没生效还不自知。
1.6 关键目录结构
以 Ubuntu/Debian 为例(不同发行版路径略有差异):
| 路径 | 作用 |
|---|---|
/etc/nginx/nginx.conf | 主配置文件,全局设置入口 |
/etc/nginx/conf.d/ | 额外配置片段,被主配置 include |
/etc/nginx/sites-available/ | 所有可用站点配置(Debian 系约定) |
/etc/nginx/sites-enabled/ | 已启用站点,软链到 sites-available |
/var/log/nginx/access.log | 访问日志 |
/var/log/nginx/error.log | 错误日志(排障第一站) |
/var/www/html/ | 默认静态站点根目录 |
/usr/share/nginx/ | 默认页面、错误页等 |
启用/停用一个站点的 Debian 惯用法,就是在 sites-enabled/ 里创建或删除软链接:
$ sudo ln -s /etc/nginx/sites-available/myapp \
/etc/nginx/sites-enabled/myapp # 启用
$ sudo rm /etc/nginx/sites-enabled/myapp # 停用
$ sudo nginx -t && sudo systemctl reload nginx
1.7 第一次验证:默认欢迎页
安装并启动后,访问 http://服务器IP/ 应该看到 "Welcome to nginx!" 页面。若看不到,按顺序排查:
- 进程是否在跑:
systemctl status nginx - 端口是否监听:
ss -ltnp | grep :80 - 防火墙是否放行:
sudo ufw allow 'Nginx Full' - 错误日志说了什么:
sudo tail -f /var/log/nginx/error.log
1.8 小结与下一步
- web 服务器负责收请求、发响应;Nginx 还能做反向代理、负载均衡、TLS 终止。
- Nginx 用事件驱动异步架构解决 C10K 问题,内存和 CPU 开销远低于 Apache 的进程/线程模型。
- 运行时是 master(管理)+ 多个 worker(干活)的多进程结构,支持零停机重载。
- 改配置的黄金流程:
nginx -t→reload。 - 下一章拆解 配置文件结构——context 层级、指令与块、include 与变量。