二、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 事件是 回调通知式 的,不用每次全遍历。
相关推荐
麦兜*41 分钟前
Spring Boot 企业级动态权限全栈深度解决方案,设计思路,代码分析
java·spring boot·后端·spring·spring cloud·性能优化·springcloud
程序员爱钓鱼3 小时前
Go语言实战案例-读取用户输入并打印
后端·google·go
Livingbody7 小时前
基于【ERNIE-4.5-VL-28B-A3B】模型的图片内容分析系统
后端
你的人类朋友8 小时前
🍃Kubernetes(k8s)核心概念一览
前端·后端·自动化运维
追逐时光者9 小时前
面试第一步,先准备一份简洁、优雅的简历模板!
后端·面试
慕木兮人可9 小时前
Docker部署MySQL镜像
spring boot·后端·mysql·docker·ecs服务器
发粪的屎壳郎9 小时前
ASP.NET Core 8 轻松配置Serilog日志
后端·asp.net·serilog
倔强青铜三10 小时前
苦练Python第4天:Python变量与数据类型入门
前端·后端·python
倔强青铜三10 小时前
苦练Python第3天:Hello, World! + input()
前端·后端·python
倔强青铜三11 小时前
苦练Python第2天:安装 Python 与设置环境
前端·后端·python