在没有IO多路复用的模型的情况下,为了支持高并发采取以下网络模型
一:阻塞IO+多线程
![d300215b757621d2d4d2ae53373b8c33.png](https://img-blog.csdnimg.cn/img_convert/d300215b757621d2d4d2ae53373b8c33.png)
![2d62b21088c71e34f861f1e3c2ea5541.gif](https://img-blog.csdnimg.cn/img_convert/2d62b21088c71e34f861f1e3c2ea5541.gif)
client连接服务器,服务器有一个线程阻塞的调用accept,accept接收到连接后,创建一个线程来读写读写,并且处理业务逻辑
阻塞IO不能充分利用CPU,后面就出现了reactor模型
二:reactor模型
特点:
1:非阻塞IO+IO多路复用(此处的IO多路复用采用的是epoll模型,关于为何选用epoll,可以看下以前的一篇文章
IO多路复用之select,poll,epoll分析
)
2:事件循环+以事件驱动或者事件回调的方式处理业务逻辑
![06ddd0a168a6162ddfd6e9746514c289.png](https://img-blog.csdnimg.cn/img_convert/06ddd0a168a6162ddfd6e9746514c289.png)
![07b226f3ba7d93ef15922ed2a0a10e03.gif](https://img-blog.csdnimg.cn/img_convert/07b226f3ba7d93ef15922ed2a0a10e03.gif)
典型的模型应用代表:redis
可以发现服务器只有一个线程,一个epoll,epoll接收到连接事件后就调用accept,接收到客户端的fd后,将fd加入到epoll,监听客户端的读写以及断开连接事件,读取到客户端的消息后,对消息进行解码,然后业务逻辑处理,处理完后编码需要回复的数据包,然后发送消息,交互完成后客户端断开连接,监听到断开连接的消息后调用close.
由上面可以看出来所有的事情都是在一个线程上跑,一个线程的处理能力也是有上限的,要是IO密集型或者是业务处理比较复杂的模型,在该网络模型上跑就会暴露其确定,为了逻辑处理的密集型问题引出下面的 单reacotor +消息队列+多线程模型
三:单reactor+消息队列+多线程
![66f75b1c919ec7b028d33d2e1cf380ed.png](https://img-blog.csdnimg.cn/img_convert/66f75b1c919ec7b028d33d2e1cf380ed.png)
![707d2f7a81bd73114895786879eeb0a4.gif](https://img-blog.csdnimg.cn/img_convert/707d2f7a81bd73114895786879eeb0a4.gif)
可以看到该模型跟reactor的区别就是在业务逻辑处理的地方加了消息队列,接收到的消息放入接收消息队列,然后业务线程从该队列取消息进行业务处理(业务线程数量最好是跟cpu核心数,业务线程中基本没有了IO操作),业务线程处理完后,将需要回复的消息放入发送队列中,当有可发送事件触发时,epoll从发送队列取消息发送。该模型很典型的应用到游戏里面,代表框架skynet,游戏中的业务是比较多的。该场景可以解决业务逻辑重的问题,但是IO密集问题没有得到解决,后面一种场景就是为解决IO秘密而生的模型,多reactor模型
四:多reactor模型 也叫one eventloop per net thread
![84a31f94eeffa9fff2a9c55dc92ecb61.png](https://img-blog.csdnimg.cn/img_convert/84a31f94eeffa9fff2a9c55dc92ecb61.png)
![3ffe10364858be6641c4c49b6d559d5d.gif](https://img-blog.csdnimg.cn/img_convert/3ffe10364858be6641c4c49b6d559d5d.gif)
多reactor指的是有多个epoll,具体多少个可以根据cpu的核心数决定,一个reactor专门负责接收连接,接收到的连接添加到sub reactor进行读写以及逻辑处理
典型的应用代表为memcached
使用多线程模型就会带来一个线程crash就会导致整个进程crash,同时数据的读取需要加锁,此时就会产生一个多reactor多进程模型
五:多进程reactor
![463e6c1ed8b8a9224b48cfaf88e56dbd.png](https://img-blog.csdnimg.cn/img_convert/463e6c1ed8b8a9224b48cfaf88e56dbd.png)
![f7812927b2c33ba3c08e50641a9941f2.gif](https://img-blog.csdnimg.cn/img_convert/f7812927b2c33ba3c08e50641a9941f2.gif)
一个main进程 fork出多个reactor进程,每个reactor都是跟上面第一种的reactor一样,这样每个reactor可以利用一个核心,充分利用多核技术,但是此处有一个问题就是当有事件接入的时候只能一个进程accept,这个时候需要引入一个accept锁,保证同一时刻只用一个进程调用accept就可以解决该问题,main process可以管理所有的reactor进程,当reactor进程crash时拉起与做一些公共的管理事件
典型的应用就是nginx
六:多reactor+消息队列+多线程
![d4615134978d8121c5c2827e1b4dba6d.png](https://img-blog.csdnimg.cn/img_convert/d4615134978d8121c5c2827e1b4dba6d.png)
![d3f0c527f98c8c75289f84f879058ce5.gif](https://img-blog.csdnimg.cn/img_convert/d3f0c527f98c8c75289f84f879058ce5.gif)
这种网络模型在实际开发中用的会比较多,在我看来主要是为了达到一个解构的目的,网络库跟逻辑处理分离