解析 Nginx 高性能的原因及使用 Nginx 做数据缓存提升查询速度
在上一篇文章【Java性能优化--Nginx篇(一)】中,我们介绍了 Nginx 的基本概念和基础应用,并使用 Nginx 的反向代理对服务水平扩展,提升系统吞吐量,接下来让我们一起解析下 Nginx 高性能原因,以及使用 Nginx 进一步提升系统性能。
一、Nginx 高性能原因分析
在如今软件开发的技术选型中会选择 Nginx 作为Web运用的容器,以及做负载均衡的软性反向代理,主要原因就是因为Nginx的高性能,而 Nginx 的高性能主要由于以下因素
- 使用 epoll 多路复用模型
- 使用 master worker 进程模型
- 使用协程机制
二、原理分析
1. epoll 多路复用模型为啥高效?
俗话说,有对比有差距,如果要弄清楚 epoll 为什么高效,需要对比其他几种模型

模型 | 工作机制 | 缺点 | 优点 |
---|---|---|---|
Java BIO | 一连接一线程 | 阻塞式的线程模型,线程资源浪费,扩展性差 | 编程简单 |
Linux Select | 单线程轮询文件描述符(FD) | 每次轮询都要遍历所有FD,效率低 | 支持多路复用 |
Linux epoll | 内核事件驱动通知回调机制 | 编程复杂 | 支持大并发,性能高 |
1.1. Java BIO 模型
✅工作原理:
服务端 ServerSocket.accept()接受链接,每当有一个客户端连接,就新建一个线程处理它,每个线程主要阻塞在 InputStream.read() 或 OutputStream.write()上,如图:

🧠 核心流程:
- 建立连接:客户端通过网卡与Linux服务器建立 socket 连接;
- 客户端发送请求:客户端程序通过网卡将数据发送出去,Linux 主机通过调用 read 系统调用,将这份请求数据从接收网卡中读取到服主机内的内核缓冲区;
- 服务端获取请求:Java服务端程序通过 read 系统调用,从Linux 内核缓冲区读取数据到用户缓冲区;
- 服务端业务处理:Java服务端在自己的用户空间中完成客户端的请求所对应的业务处理。
- 服务端返回数据:Java服务端完成数据处理后,构建好响应数据,从用户缓冲区通过 write 系统调用,将数据写入 Linux 内核缓冲区;
- 发送响应数据给客户端:Linux 系统将内核缓冲区中的数据通过 write 系统调用,将内核缓冲区的数据写入网卡,网卡通过底层。
总结:以上就是Java BIO 一次完整请求的过程,在此过程中线程会一直在阻塞中等待系统完成 read 和 write 操作,而 read 和 write 调用是由操作系统自动完成,用户程序无感知。
❌缺点:
假设有10个客户端连接进来,服务端就得创建10个线程,每个线程都阻塞等待客户端发消息,线程资源消耗大,每个连接都要一个线程,并发能力差,线程切换成本高,CPU开销大。
1.2. Linux Select 模型(IO 多路复用)
与 Java BIO 相比,Select 模型 不用一个连接就使用一个线程处理了,而是使用一个线程监听多个 socket 连接,大大减少了CPU 上下文频繁切换带来的性能消耗,其工作原理如下所示。
✅工作原理
-
用户态构建监听集合并调用
select()
。 -
内核将用户态的集合拷贝到内核态,并轮询检测每个 fd(文件描述符) 的就绪状态。
-
如果某个 fd 没有就绪,内核将当前线程挂到该 fd 的 等待队列 中,等待事件发生;
-
当 fd 事件发生时,内核会唤醒等待队列中的线程,遍历就绪的 fd 进行相应的 I/O 操作。
❌缺点
- 监听的数量太少,最多只能同时监听1024个套接字,不适宜于广域网开发;
-
- 随着select的持续使用,会产生大量的拷贝开销和挂载开销;
- 通过轮询遍历的方式,遍历所有文件描述符,筛选出哪些可读/可写,非常消耗CPU,会导致服务器吞吐能力会非常差。
如果要详细了解 select 模型可以参考此文章:select详解&如何使用select模型实现简易的一对多服务器
1.3. Linux Epoll 模型(事件驱动 IO,多路复用升级版)
✅ 工作原理:
- 使用
epoll_create()
创建 epoll 实例。 - 使用
epoll_ctl()
注册 socket 和你关心的事件(比如可读)。 - 使用
epoll_wait()
等待事件。 - 在epoll 模型中,还是通过监听 socket 连接是否发生变化,并对每个连接设置回调函数,如果发生变化则直接唤醒并执行回调函数,而不需要遍历 fd 进行相应的 I/O 操作。
🧠 核心机制:
- 内核和用户空间之间建立了一种 回调通知机制(event ready) 。
- 支持 边缘触发 (Edge Triggered)和 水平触发(Level Triggered)。
- 支持超大连接数(上万、十万级别),适合高并发服务端。
🔥 优点:
- 性能比 select 高很多。
- 没有 FD 数量限制。
- IO 事件是 回调通知式 的,不用每次全遍历。