高并发之nginx架构

根据:单机并发简介https://blog.csdn.net/p731heminyang/article/details/154754364https://blog.csdn.net/p731heminyang/article/details/154754364

在硬件性能有限的早期,C10K 问题(即单机如何高效处理上万并发连接)成为网络服务架构的一大挑战。为应对这一瓶颈,操作系统和应用程序层面相继引入了多项关键优化------从非阻塞 I/O、I/O 多路复用(如 epoll、kqueue),到事件驱动模型和高效的内存管理机制。

如今,Nginx 已成为高并发场景下的事实标准,广泛应用于全球各大互联网系统。它之所以能轻松支撑数万乃至数十万并发连接,正是深度结合了现代硬件特性与操作系统能力的结果。通过深入理解 Nginx 在硬件与系统层面的设计与优化策略,我们不仅能掌握其高性能的根源,也能更好地将其应用于实际工程实践。

一、简介

Nginx(发音为 "engine-x")是一款高性能、轻量级的开源 Web 服务器和反向代理服务器,同时也支持负载均衡、HTTP 缓存、流媒体传输等功能。它最初由俄罗斯开发者 Igor Sysoev 于 2004 年发布,旨在解决 C10K(即同时处理一万个并发连接)问题。如今,Nginx 已成为全球最流行的 Web 服务器之一,广泛应用于高并发、高可用性的互联网服务架构中。

1.1 特性

  • 高并发、低内存消耗:采用事件驱动、异步非阻塞的架构模型(如 epoll/kqueue),能高效处理大量并发连接。
  • 反向代理与负载均衡:支持 HTTP、HTTPS、TCP/UDP 等协议的反向代理,并提供多种负载均衡算法。
  • 静态文件服务:高效处理静态资源(如 HTML、CSS、JS、图片等)。
  • 模块化设计:功能通过模块实现,核心模块 + 第三方模块灵活扩展。
  • 热部署与平滑升级:支持不停机更新配置或升级版本。
  • 缓存机制:可作为 HTTP 缓存服务器,提升响应速度。
  • 安全控制:支持访问控制、限速、SSL/TLS 加密等安全功能。

二、历史背景

  • 开发者:Igor Sysoev(俄罗斯工程师)
  • 动机:解决 C10K 问题(即单机处理 10,000+ 并发连接)
  • 灵感来源:Apache 在高并发下的性能瓶颈(每个连接一个进程/线程)
  • 首次公开发布2004 年 10 月 4 日 (版本 0.1.0

初始版本功能:

尽管是早期版本,但已具备 Nginx 核心架构和基础能力:

核心架构

  • Master-Worker 多进程模型
  • 事件驱动 + 非阻塞 I/O (基于 kqueue / select,Linux 下尚未用 epoll)
  • 配置文件驱动nginx.conf

基础 HTTP 功能

  • 静态文件服务(HTML、图片等)
  • 虚拟主机(server 块,基于 IP 或端口)
  • 基本的 MIME 类型支持
  • 日志记录(access log)

三、核心架构分析

这里关于业务逻辑就不分析了,只分析下他是如何做到高并发的,由于不讲业务逻辑部分,所以会比较简单。

为了达到c10K,进行了如下优化:

  • nginx选取了性能最高的C语言开发尽可能的发挥硬件性能
  • 为了更好地适应任务调度,采用了Master-Worker 多进程模型
  • 避免阻塞和轮询,采用了事件驱动 + 非阻塞 I/O(初版为select/poll ,这里直接跳过为epoll)
  • 文件操作,采用零拷贝技术,直接硬盘→内核→socke(网卡)不经过用户态,减少内存使用和cpu计算

3.1 Master-Worker 多进程模型

Master 进程:1 个,由启动用户(如 root)运行

Worker 进程:N 个,默认等于 CPU 核心数(worker_processes auto;)

Master-Worker模型

Master 进程(管理者):

  • 读取并验证配置文件(nginx.conf)
  • 绑定监听端口(如 80/443),创建监听 socket
  • fork 出多个 Worker 子进程
  • 接收并处理外部信号:
  • SIGHUP:重载配置(reload)
  • SIGUSR1:重新打开日志文件(log rotate)
  • SIGQUIT / SIGTERM:优雅关闭或强制退出
  • 监控 Worker 状态:若 Worker 异常退出,可自动重启(取决于配置)

Worker 进程(工作者):

  • 继承 Master 创建的监听 socket
  • 每个 Worker 独立运行一个事件循环(event loop)
  • 使用 epoll(Linux)、kqueue(BSD)等机制监听所有连接
  • 异步、非阻塞地处理 HTTP/TCP 请求
  • 完全独立:进程间无共享内存(除只读配置外),避免锁竞争

为什么采用多进程而非多线程:

对比项 多进程(Nginx) 多线程(Apache prefork/worker)
隔离性 进程崩溃不影响其他 Worker 线程崩溃可能导致整个进程挂掉
内存开销 稍高(但 COW 优化) 较低,但线程栈仍需内存
编程复杂度 无共享状态,无需锁 需处理线程同步、锁竞争
扩展性 天然利用多核 受限于 GIL(某些语言)或锁瓶颈
稳定性 极高 中等

Nginx 选择 多进程 + 单线程事件循环,是为了在性能、稳定性和简洁性之间取得最佳平衡。

3.2 完整流程-epoll(epoll 与 Master-Worker 的协同机制)

Master-Worker模型结合epoll模型,完美的把硬件的性能提升上来,下面是流程

在 Nginx 中,epoll 并非由 Master 进程使用,而是完全运行于每个 Worker 进程内部。这种设计实现了"控制面"与"数据面"的彻底分离:

  • Master 负责管理(Control Plane):不碰任何网络 I/O,只做进程调度与配置加载;
  • Worker 负责处理(Data Plane):每个 Worker 独立持有 epoll 实例,全权处理连接生命周期

请求处理全流程(结合 epoll):

  1. 启动阶段

    • Master 创建监听 socket(如 0.0.0.0:80),但不进入事件循环
    • fork 出 N 个 Worker 进程,所有 Worker 继承该监听 socket 的文件描述符(FD)
  2. 连接到来

    • 内核接收到 TCP SYN 包,完成三次握手,将新连接放入 accept 队列。
    • 所有 Worker 的 epoll 实例均监听该监听 FD,因此可能多个 Worker 被唤醒(惊群问题)。
  3. accept 竞争

    • 若启用 accept_mutex on(旧版默认),仅一个 Worker 能抢到互斥锁并调用 accept()
    • 若启用 reuseport(推荐),内核直接将连接分发给某个 Worker,无竞争、无锁、无惊群
  4. 注册新连接到 epoll

    • 成功 accept 后,Worker 将新连接的 socket FD 加入自己的 epoll 实例:

      复制代码
      epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &event);

      此后该连接的所有读写事件均由同一个 Worker 异步处理 ,保证请求处理的局部性(cache-friendly)。

  5. 事件驱动处理

    • Worker 调用 epoll_wait() 阻塞等待事件:

      复制代码
      int n = epoll_wait(epfd, events, max_events, timeout);
    • 当有数据可读(如 HTTP 请求到达)或可写(如后端响应返回),epoll 立即返回就绪 FD 列表。

    • Worker 非阻塞地读取请求、解析、代理、生成响应、写回客户端,全程无 sleep、无阻塞。

  6. 连接复用或关闭

    • 若为 Keep-Alive 连接,FD 继续保留在 epoll 中,等待下一次请求;
    • 否则,关闭 FD,从 epoll 移除,释放资源。

单个 Worker 可同时监控 数万个 FD ,而 epoll_wait() 的时间复杂度为 O(1) (仅返回活跃事件),彻底摆脱了 select/poll 的 O(n) 扫描瓶颈。

四、Nginx 如何突破单机并发五大瓶颈

结合:让 CPU 忙于计算,而非等待 I/O;让资源用在刀刃上,而非浪费在切换与拷贝

Nginx 的高性能不仅是软件设计的结果,更依赖底层硬件与操作系统的配合:

具体优化如下:

瓶颈类型 传统方案问题 Nginx 优化策略
1. 进程/线程调度 每连接一线程 → 内存爆炸、上下文切换开销大 单线程事件循环 + 多进程 • 每 Worker 无阻塞处理万级连接 • 无线程栈开销(节省 2MB/线程)
2. 内存消耗 每连接占用 MB 级内存 轻量连接结构 • 内核 struct sock ≈ 3--8KB • 应用层无额外线程栈 • 32GB 内存可支撑 200 万+ 空闲连接
3. 文件描述符限制 默认 1024,无法扩展 系统级调优ulimit -n 1000000worker_rlimit_nofile • Linux 支持单进程百万 FD
4. I/O 多路复用效率 select/poll O(n) 扫描,拷贝 FD 集合 epoll 事件驱动 • 内核维护红黑树 + 就绪链表 • epoll_wait() 仅返回活跃 FD • 时间复杂度 O(1),无无效遍历
5. 磁盘 I/O 瓶颈 同步 read/write 阻塞线程 零拷贝 + 异步 I/Osendfile():磁盘 → 网卡,绕过用户态 • aio(Linux AIO 或 thread pool)处理大文件

https://blog.csdn.net/p731heminyang/article/details/154754364由于这里是1w连接(只是连接不是并发,并发包含业务处理,后续篇章讲解),我们通过之前的单机并发 计算,如果调优内核参数:

1、每个连接申请大概16kb内存

2、一个进程大概最多支持1048576个句柄(已经达到百万了,不是瓶颈)

3、由于采用事件模式epoll,事件复杂度为O(1),cpu不是瓶颈没问题(注意连接数,没有数据处理,当然如果是https的连接还涉及到加解密计算那么cpu也会成为瓶颈,这里主要是设计等待io问题)

那么瓶颈主要是在内存,那么16kbx10000 约为157M 就可以搞定1w连接,所以老式电脑完全没问题,当然要注意 "是连接数,不是qps、tps" 这种哈,这种不再单单算一个连接,而是整体业务消耗了。

五、结束:

Nginx 的成功,本质上是 对操作系统能力的极致利用

  • 它没有发明新理论,而是将 epoll、sendfile、mmap、SO_REUSEPORT 等内核特性组合成一套高效流水线;
  • 它摒弃了"为每个连接分配资源"的旧范式,转而采用"事件驱动 + 资源复用"的新模型;
  • 它证明了:单机百万并发并非神话,而是合理架构 + 系统调优 + 硬件升级的必然结果
相关推荐
边疆.2 小时前
【Linux】进程创建、进程终止、进程等待和进程程序替换
linux·运维·服务器·vim·进程控制·进程等待·进程替换
Y淑滢潇潇2 小时前
RHCE Day5 SELinux
linux·运维·rhce
是垚不是土3 小时前
运维新人踩坑记录:Redis与MySQL生产故障排查&优化手册
运维·数据库·redis·mysql·云计算·bootstrap
snpgroupcn3 小时前
如何在SAP中实现数据验证自动化?5天缩短验证周期,提升转型效率的3大关键策略
运维·人工智能·自动化
optimistic_chen3 小时前
【Linux 系列】Linux 命令/快捷键详解
linux·运维·服务器·ubuntu·命令行·快捷键
袖手蹲4 小时前
树莓派 5 Trixie 镜像 + Docker 架设 Eclipse Mosquitto 与 ESP32 双向 MQTT 交互
运维·docker·容器
山卡拉噶5 小时前
在Linux中安装Kdump调试环境
linux·运维·服务器
离&染5 小时前
宝塔nginx一个域名部署两个前端和两个后端(VUE3)
前端·nginx
℡終嚸♂6805 小时前
红帽系统(RHEL 8/9)安装与配置Nginx全攻略
运维·chrome·nginx