二、Java性能优化--Nginx篇(二)

解析 Nginx 高性能的原因及使用 Nginx 做数据缓存提升查询速度

在上一篇文章【Java性能优化--Nginx篇(一)】中,我们介绍了 Nginx 的基本概念和基础应用,并使用 Nginx 的反向代理对服务水平扩展,提升系统吞吐量,接下来让我们一起解析下 Nginx 高性能原因,以及使用 Nginx 进一步提升系统性能。

一、Nginx 高性能原因分析

在如今软件开发的技术选型中会选择 Nginx 作为Web运用的容器,以及做负载均衡的软性反向代理,主要原因就是因为Nginx的高性能,而 Nginx 的高性能主要由于以下因素

  1. 使用 epoll 多路复用模型
  2. 使用 master worker 进程模型
  3. 使用协程机制

二、原理分析

1. epoll 多路复用模型为啥高效?

俗话说,有对比有差距,如果要弄清楚 epoll 为什么高效,需要对比其他几种模型

模型 工作机制 缺点 优点
Java BIO 一连接一线程 阻塞式的线程模型,线程资源浪费,扩展性差 编程简单
Linux Select 单线程轮询文件描述符(FD) 每次轮询都要遍历所有FD,效率低 支持多路复用
Linux epoll 内核事件驱动通知回调机制 编程复杂 支持大并发,性能高
1.1. Java BIO 模型
✅工作原理:

服务端 ServerSocket.accept()接受链接,每当有一个客户端连接,就新建一个线程处理它,每个线程主要阻塞在 InputStream.read() 或 OutputStream.write()上,如图:

🧠 核心流程:
  1. 建立连接:客户端通过网卡与Linux服务器建立 socket 连接;
  2. 客户端发送请求:客户端程序通过网卡将数据发送出去,Linux 主机通过调用 read 系统调用,将这份请求数据从接收网卡中读取到服主机内的内核缓冲区;
  3. 服务端获取请求:Java服务端程序通过 read 系统调用,从Linux 内核缓冲区读取数据到用户缓冲区;
  4. 服务端业务处理:Java服务端在自己的用户空间中完成客户端的请求所对应的业务处理。
  5. 服务端返回数据:Java服务端完成数据处理后,构建好响应数据,从用户缓冲区通过 write 系统调用,将数据写入 Linux 内核缓冲区;
  6. 发送响应数据给客户端: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 事件是 回调通知式 的,不用每次全遍历。
相关推荐
孟紫瑶3 分钟前
C#语言的游戏引擎
开发语言·后端·golang
雷渊7 分钟前
Redisson如何保证解锁的线程一定是加锁的线程?
java·后端·面试
AronTing7 分钟前
10-Spring Boot 启动性能优化实战
后端·面试
{⌐■_■}21 分钟前
【go】slice的浅拷贝和深拷贝
开发语言·后端·golang
〆、风神1 小时前
Spring Boot 自定义 Redis Starter 开发指南(附动态 TTL 实现)
spring boot·redis·后端
Asthenia04121 小时前
HashMap 扩容机制与 Rehash 细节分析
后端
DataFunTalk1 小时前
不是劝退,但“BI”基础不佳就先“别搞”ChatBI了!
前端·后端
星星电灯猴1 小时前
flutter项目 发布Google Play
后端
用户9704438781162 小时前
按图搜索1688商品(拍立淘)API 返回值说明
javascript·后端·算法
Fly_hao.belief2 小时前
Spring Boot 框架注解:@ConfigurationProperties
java·spring boot·后端