概述
对于网络服务器后端开发,为满足不同并发场景的须要,一般来说,不外乎几种常见的并发模型,除了一些教学场景罕用的单线程、多过程(线程)的服务器实现外,生产用的服务器,个别都会思考应用 IO 多路复用模型。
而常见的 IO 多路复用场景,能够设计得很简略,也能够设计得比较复杂,个别依据业务须要而定。本文总结了一些比拟常见的服务器并发模型,根本涵盖了 大部分业务场景。在理论业务开发的技术选型时,可依据场景,选取一款稳固、牢靠的网络模型,还是非常要害的。
模型一:单线程 Accept(无 IO 复用)
模型剖析
- 主线程 main thread 执行阻塞 accept,每次客户端 connect 连贯过去,main thread 中 accept 响应并建设连贯
- 创立连贯胜利,失去 connect fd 套接字后,仍然在 main thread 串行解决套接字读写,并解决业务
- 在解决业务时,如果有新客户端 connect 过去,server 无响应,直到以后 socket 全副业务处理完毕(完结 while 循环)
- 以后客户端处理完毕之后,敞开连贯,解决下一个客户端申请
优缺点
长处
- socket 编程流程清晰且简略,适宜学习应用,理解 socket 根本编程流程
毛病
- 该模型并非并发模型,是串行服务器,同一时刻,监听并响应的最大网络申请量为 1,即并发量为 1
- 仅适学习根本 socket 编程,不适宜任何服务器 server 构建
模型二:单线程 Accept + 多线程读写业务(无 IO 复用)
模型剖析
- 主线程 main thread 阻塞在 accept,每次客户端 connect 连贯过去,main thread 中 accept 响应并建设连贯
- 创立连贯胜利,失去 connect fd 套接字后,创立一个新的线程 thread 来解决客户端的读写业务,mian thread 仍然回到 accept 阻塞期待新客户端
- thread 通过套接字 connect fd 与客户端进行读写操作
- server 在解决业务时,如果有新的客户端连贯过去,main thread 中 accept 仍然能够响应并建设连贯,反复上述过程
优缺点
长处
- 基于模型 1 的优化,反对了并发的个性
- 应用比拟灵便,一个客户端对应一个线程独自解决,server 解决业务的内聚性比拟高,客户端无论如何读写,服务端 均会有一个 线程做资源响应
毛病
- 随着客户端梳理增多,须要开拓的线程数量也减少了,和 server 线程的数量是 1:1 的关系,因而对于高并发场景,线程数量受到硬件的瓶颈,线程过多也会 减少 CPU 的切换老本,升高 CPU 利用率
- 对于长连贯,客户端一旦无业务读写,只有不敞开,server 就应该对放弃这个连贯的状态(心跳查看,健康检查机制),占用连贯资源和线程的开销
- 仅适宜客户端数量不大的场景,且可控的场景来应用
- 该模型仅适宜学习根本的 socket 编程,不适宜做并发服务器
模型三:单线程多路 IO 复用
模型剖析
- 主线程 main thread 创立 listen fd 之后,采纳多路 IO 复用机制(如 select、epoll)进行 IO 状态阻塞监控,有 client 连贯申请,IO 复用机制检测到 listen fd 触发读事件,则进行 accept 建设连贯,并将新生成的 connect fd 退出到监听 IO 汇合中
- client 再次进行失常读写业务申请,main thread 的多路 IO 复用机制阻塞返回,会触发该套接字 的读写事件等
- 对于 client 的读写业务,server 仍然在 main thread 执行流程继续执行,此时如果有新的客户端 connect 申请过去,server 将没有即时响应
- 等到 server 解决完一个连贯的读写操作,持续回到多路 IO 复用机制阻塞,其余连贯过去才能够失常执行
优缺点
长处
- 单流程体解决了能够同时监听多个客户端读写状态模型,不须要 1:1 客户端的线程数量关系
- 多路 IO 复用机制 是阻塞的,非忙轮询的状态,不会节约 CPU 资源,对 CPU 的利用率较高
- 对于连接数较多,然而并发不大的场景,或对实时性没有特地严格的场景,该模型曾经足够应用
毛病
- 尽管能够监听读个客户端的读写状态,然而同一时间内,只可能解决一个客户端的读写操作,实际上读写业务并发为 1
- 当多个客户端拜访 server,业务是串行执行,大量申请的会有排队提早景象。
模型四:单线程多路 IO 复用 + 多线程读写业务(业务工作池)
模型剖析
- 主线程 main thread 创立 listen fd 后,采纳多路 IO 复用机制(如 select、epoll)进行 IO 状态阻塞监控,有 client 客户端 connect 申请,IO 复用机制检测到 listenfd 触发读事件,则进行 accept 建设连贯,并将新生成的 connect fd 退出到监听 IO 汇合中
- 当 connect fd 有 可读音讯,触发读工夫,并进行读写音讯
- main thread 依照固定协定读取音讯,并且交给 worker pool 工作线程池,工作线程池在 server 启动之前就曾经开启固定数量的 thread,外面的线程只解决音讯 业务,不进行套接字读写操作
- 工作池解决完业务,触发 connect fd 写事件,将回执客户端的音讯通过 main thread 写给对方
- 即:main thread 只解决 IO 阻塞监听以及具体的读写操作,读写到的数据交给具体的线程池解决,让 main thread 专一于解决 IO 事件
- 相似于 Redis 的解决机制
优缺点
长处
- 将业务解决的局部,通过工作池分离出来,可能缩小客户端拜访 server 导致业务串行执行会有大量申请排队的延迟时间
- 实际上读写的业务并发为 1,然而业务流程的并发为线程池数量,放慢了业务解决的并行效率
毛病
- 读写仍然是 main thread 独自解决,最高的读写并行通道仍然是 1
- 尽管多个 worker thread 解决业务,最初返回给 client 仍旧也须要排队,因为进口还是 main thread 的一个通道
模型五:单线程 IO 复用 + 多线程 IO 复用
模型剖析
- server 在 启动监听前,开拓固定数量(N)的 线程,用 thread poll 线程池治理
- 主线程 main thread 创立 listen fd 之后,采纳 IO 多路复用机制(如 select、epoll)进行 IO 状态阻塞监控,有 client 连贯申请,IO 复用机制 检测到 listen fd 触发读事件,则进行 accept 建设连贯,并将新生成的 connect fd 分发给 thread pool 中的某个线程进行监听
- thread pool 中的每个 thread 都启动 IO 多路复用机制,用来监听 main thread 建设胜利并且散发下来的 connect fd 的读写事件,解决对应的读写业务,并将解决完的后果通过该 thread 本人的 IO 多路复用机制回执给客户端
优缺点
长处
- 将之前的 main thread 单流程的读写,扩散到多线程来实现,这样就减少了同一时刻 读写的并行通道,并行通道的数量 N,N 就是线程池的数量
- server 同时监听 connect fd 的数量,简直是成倍增加,之前的全副监控数量取决于 main thread 的多路 IO 复用机制的最大限度,所以实践上单点 server 最高响应并发数量应该是之前的 N 倍(N 是 线程池数量,倡议线程数量和 CPU 外围数 1:1)
- 如果良好的 线程池数量可 CPU 外围数适配,那么能够尝试将 CPU 与 thread 绑定,从而升高 CPU 的切换频率,进步每个 thread 解决正当业务的效率,升高 CPU 的切换老本
- memchached 的并发模型与该模型比拟相似
毛病
- 尽管监听的并发数量晋升,然而最高的读写并行通道仍然为 N,并且多个身处于同一个 thread 的客户端,会呈现读写排队景象,实际上每个 thread 模型与单线程 IO 多路复用机制是统一的
模型六:单过程 IO 复用 + 多过程 IO 复用
模型剖析
- 与单线程 IO 复用 + 多线程 IO 复用(线程池)无太大差别
-
不同点
- 过程和线程的内存布局不同,导致 main process(主过程)不再进行 accept 操作,而是将 accept 过扩散到各个子过程中
- 过程的个性,资源独立,所以 main process 如果 accept 胜利的 fd,其余过程无奈资源共享,所以须要各个过程自行 accept 创立连贯
- main process 只是监听 listen fd 的状态,一旦触发读事件(有新连贯申请),通过一些 IPC(过程间通信,如信号、共享内存、管道等),让各自子过程 process 竞争 accpet 实现连贯建设,并各自监听
优缺点
- 与单线程 IO 复用 + 多线程 IO 复用(线程池)无太大差别
-
不同点:
- 多过程内存资源空间占用略微大一些
- 多过程模型平安稳定性较强,这也是各自过程互不烦扰的特点导致
- 实际上每个子过程 process 都是一个单线程 IO 多路复用模型
模型七:单线程 IO 复用 + 多线程 IO 复用 + 多线程
模型剖析
- server 在启动监听之前,开拓固定数量(N)的线程,用 thread pool 线程池治理
- 主线程 main thread 创立 listen fd 之后,采纳 IO 多路复用机制(如 select、epoll)进行 IO 状态阻塞监控,有 client 连贯申请,IO 复用机制 检测到 listen fd 触发读事件,则进行 accept 建设连贯,并将新生成的 connect fd 分发给 thread pool 中的某个线程进行监听
- thread pool 中的每个 thread 都启动 IO 多路复用机制,用来监听 main thread 建设胜利并且散发下来的 connect fd 的读写事件,一旦有某个 connect fd 的读写事件被触发,立刻开拓一个新的 线程开解决 IO 读写业务
- 当某个线程解决完以后的读写业务,如果以后 connect fd 没有被敞开,那么将以后 fd 从新加回到 thread pool 的 IO 复用汇合,并将本身线程销毁
优缺点
长处
- 除了可能保障同时响应最高的并发数,又可能解决读写并行通道的局限问题
- 同一时刻读写并行通道,达到最大化极限,一个客户端能够对应一个独自的执行流程解决读写业务
毛病
- 该模型过于理想化,要求 CPU 外围数足够大
- 如果硬件 CPU 数量无限,那么该模型就造成大量 CPU 切换的老本节约。
- 理论开发中,简直用不到如此简单的网络模型,以后风行的开源网络组件中,也没有哪一款软件做到了如此简单的水平
本专栏知识点是通过 < 零声教育 > 的零碎学习,进行梳理总结写下文章,对 C /C++ 课程感兴趣的读者,能够点击链接,查看具体的服务:C/C++Linux 服务器开发 / 高级架构师