网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
而常见的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多路复用机制回执给客户端
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新