Web 服务架构概览
做后端开发或运维,绕不开对 Web 服务底层机制的理解。Apache 和 Nginx 是两大主流选择,它们的进程模型直接决定了并发处理能力。
Apache 的三种经典模式
Prefork 模型(预派生)
这是最传统的模式。主进程启动多个子进程,每个子进程单线程处理请求。它使用 select 模型,最大并发通常在 1024 左右。虽然内存占用较高,但胜在稳定,故障隔离性好。适合访问量中等的场景,但不太适合高并发。
Worker 模型(多进程 + 多线程) 为了解决 Prefork 内存高的问题,Worker 引入了线程。主进程下挂多个子进程,每个子进程包含固定数量的线程。相比 Prefork,内存占用更低,能处理更多请求。不过要注意,长连接(keepalive)会长期占用线程,高并发下容易出现无可用线程的情况。
Event 模型(事件驱动)
从 2.4.X 版本开始支持,基于 epoll 事件驱动。核心优化在于解决了 keepalive 连接空占线程的问题:有真实请求时才分配服务线程,执行完立即释放。单线程响应多请求,内存少,高并发表现优秀,但需要注意线程安全问题。
Nginx 简介
Nginx 由俄罗斯工程师 Igor Sysoev 开发,最初是为了应对 Rambler.ru 的高流量需求。2004 年发布首个版本,如今已被 F5 收购。它的核心代码精简高效,被天猫、淘宝、京东等一线大厂广泛使用。作为高性能 Web 服务器,它支持 HTTP、反向代理、邮件服务器等多种角色,且 1.9 版本以上开启 stream 模块后还能支持 TCP/UDP 负载均衡。
服务端 I/O 流程解析
理解 I/O 模型之前,得先搞清楚数据是怎么流动的。
基本概念
I/O 即输入输出。IOPS 衡量磁盘性能,指每秒处理的 I/O 请求数。完整的 I/O 过程涉及用户空间进程与内核空间数据的交换。由于内核与用户空间严格隔离,数据必须经过拷贝才能完成交互。
通用流程
无论是磁盘还是网络 I/O,通常经历两个阶段:
- 数据准备:将数据从文件加载到内核内存缓冲区,这一步耗时较长。
- 数据拷贝:将数据从内核缓冲区拷贝到用户进程内存,这一步相对较快。
关键概念辨析
- 同步 vs 异步:关注通知机制。同步是被调用者不主动通知,需调用者查询;异步是被调用者通过回调或状态主动告知。
- 阻塞 vs 非阻塞:关注等待状态。阻塞是 IO 操作完成后才返回,期间进程挂起;非阻塞是调用后立即返回状态,无需等待完成。
五种网络 I/O 模型对比
1. 阻塞型 I/O (Blocking IO)
用户线程发起 read 系统调用后,一直等待直到数据就绪并拷贝完成。全程阻塞,CPU 利用率低。优点是程序简单,缺点是并发能力差,每个连接需独立进程/线程。Apache prefork 模式就属于此类。
2. 非阻塞型 I/O (Nonblocking IO)
发起 IO 请求后立即返回,如果没有数据会返回错误码(如 EWOULDBLOCK)。用户线程需要不断轮询,直到数据到达。优点是不阻塞,缺点是轮询消耗 CPU,实际很少单独使用。
3. 信号驱动式 I/O (Signal-driven IO)
注册信号处理回调函数,内核数据就绪时发送 SIGIO 信号触发回调。等待数据时进程不阻塞,资源利用率高。但如果大量 IO 操作,可能因信号队列溢出导致通知失效。
4. 异步 I/O (Asynchronous IO)
这是真正的异步。调用 aio_read 后立即返回,内核完成数据准备和拷贝后主动通知。IO 两个阶段进程均非阻塞。优点是充分利用 DMA,IO 与计算重叠;缺点是操作系统实现复杂,Linux 2.6 才引入,常用 libevent/libuv 等库封装。
5. 多路复用 I/O (Multiplexing)
单个线程监控多个文件描述符,通过 实现。阻塞发生在 调用上,而非实际 IO 操作。相比单线程单 IO,它能同时监控多个 IO,是高并发的主流方案。注意,NIO 需与多路复用配合才有意义。

