目录
一.前言
1.目标
2.边界说明
二.i/o模型
1.阻塞i/o
简介:
特点:
2.非阻塞i/o
简介:
特点:
3.信号驱动i/o
简介:
特点:
4.异步i/o
简介:
特点:
5.多路转接i/o
简介:
特点:
三.高并发服务器设计
1.架构模型选择:主从 Reactor 多线程模型
核心架构:
2.设计初衷与解决的痛点:
为什么要引入多 Reactor 模式:
为什么要引入线程池:
3.扩展:
一.前言
1.目标
深入剖析常见的网络 I/O 模型底层原理,此为基础,设计出高并发、高性能的网络服务器。
2.边界说明
本篇内容聚焦于操作系统层面的用户态与内核态交互,重点分析系统调用、进程调度与缓冲区管理,暂不展开讨论网卡 DMA、硬中断等底层硬件细节。
二.i/o模型
1.阻塞i/o
简介:
这是 Linux 系统中最基础、最传统的 I/O 模型。一次完整的输入或输出操作通常包含两个核心阶段:等待数据就绪和数据拷贝。在阻塞 I/O 模型中,调用进程在这两个阶段都会被迫挂起,交出 CPU 控制权。
特点:
代码逻辑呈纯线性顺序执行,符合人类直觉,开发与维护成本极低。
非忙轮询,进程会被挂载到等待队列,不消耗 CPU 算力。直到对应的 I/O 事件真正就绪,内核才会唤醒该进程继续执行。
由于由于无需引入额外的事件监听和分发机制,其系统调用链路最短,面对单连接环境具有极致的性能和低延迟。
由于存在多次阻塞,执行速度完全受制于外部网络延迟、对端处理速度,若要支持高并发,只能采用“one thread one loop”模式,线程多次切换导致开销暴涨,性能低下。
2.非阻塞i/o
简介:
发起系统调用时,如果内核缓冲区中的数据尚未就绪,系统调用不会挂起当前进程,而是立即返回一个特定的错误码,用户还可以继续调用。
相比于阻塞i/o,在等待数据就绪阶段不再阻塞,但数据拷贝阶段依然阻塞执行。
特点:
轮流探测多个连接,不会因为某个连接没有输入而被彻底死锁挂起,可以实现低连接并发服务,但面对高并发环境吞吐极差,延时极高。
等待数据间隙交替执行各种任务,提升利用率。但忙轮询状态,严重消耗CPU,容易造成CPU空转等情况。
3.信号驱动i/o
简介:
利用内核信号机制通知数据就绪的模型,预先注册信号处理函数,数据准备完毕后发送信号,触发信号信号回调处理,执行数据拷贝操作。
特点:
避免了非阻塞 I/O 中高频调用带来的 CPU 空转与内核态/用户态频繁切换开销。但信号产生、传递以及处理仍然具有较高成本,并且存在信号机制带来的延迟。
单线程可专心处理计算密集型任务,无需显式管理轮询循环。
4.异步i/o
简介:
遵循“通知完成”机制,用户进程向操作系统发起读写请求,并直接把目标缓冲区地址和大小交给内核,然后调用立即返回;内核在后台自主完成等待数据与将数据拷贝到用户缓冲区这两个阶段,全部搞定后才通知应用程序直接消费数据。
相比于上面两种i/o,等待数据就绪与数据拷贝阶段都不会阻塞。
特点:
用户进程完全摆脱了所有阻塞等待,可以做到单核心百万级的高并发。
架构复杂,代码维护成本高。
5.多路转接i/o
简介:
单线程下,依赖操作系统内核,同时监控多个文件描述符的就绪状态。当描述符准备好读写事件时,不会优先读写,而是根据接口返回做判断,对事件就继续的文件描述符发起真正的读写操作。
特点:
单线程/单进程即可高效管理数以万计甚至数十万的长连接,但不适合长时间计算或死循环,会降低系统响应速率等,拖垮事件循环上的所有连接。
三.高并发服务器设计
1.架构模型选择:主从 Reactor 多线程模型
核心架构:
基于 I/O 多路复用技术,采用“主从 Reactor + 工作线程池”的组合设计。
主反应堆:专职监听服务端端口,集中处理所有新客户端的连接请求,并将建立好的连接分配给 Sub Reactor。
从反应堆:接管已被分配的连接,监听这些文件描述符的读写事件,负责真正的 I/O 数据接收与发送。
工作线程池:负责接收 Sub Reactor 读取到的数据,进行协议解析、业务计算与逻辑处理,最后将结果交回给 Sub Reactor 发送。
2.设计初衷与解决的痛点:
为什么要引入多 Reactor 模式:
在单 Reactor 模式下,接收新连接(accept)和处理存量连接的 I/O 读写共用同一个事件循环。当面临瞬时高并发的连接洪峰时,如果 Reactor 恰好正在处理其他连接的大量 I/O 操作,就会来不及执行accept。这会导致操作系统的全连接队列迅速溢出,进而造成大量新客户端的连接请求被内核直接丢弃。多 Reactor 模式可以将“连接建立”与“数据读写”彻底物理隔离,Main Reactor 可以极速地响应建连请求保障了服务器在极端突发流量下的高并发接入能力。
为什么要引入线程池:
如果业务处理逻辑复杂,或包含耗时操作,直接在 Reactor 线程中执行会“卡死”整条流水线。这会导致其他成百上千个已经就绪的网络事件被迫排队等待,引发整体系统响应的高延迟甚至假死。线程池可将重度的业务计算剥离到后台线程池执行,让从反应堆继续监听和搬运下一波网络数据,完美保障了网络 I/O 层的高吞吐与极低延迟。
3.扩展:
- 针对网络异常或断电情况下导致的大量死连接,可扩展时间轮、心跳等机制定期检查连接活跃度,剔除超时未响应的存量连接,保障系统资源的良性循环。
- 对线程池业务处理频繁,可修改底层内存分配机制,如ptmalloc替换成tcmalloc,或直接预分配足够大小的内存,络收发时循环复用,实现“零分配”开销。