查看原文
其他

几种高性能网络模型

后端技术指南针 后端技术指南针 2021-02-01
如何实现高并发是个热门的话题,不同的语言和平台有不同的处理手段,本文主要讲述在Linux平台下C/C++语言实现的几种高性能网络模型。
通过本文可以了解到以下内容:
  • IO复用技术

  • 事件处理模型

  • 几种并发模型

  • Memcache的网络模型


1.IO复用技术

IO复用是一种机制,简单说就是IO事件的到来、读写、异常等情况都有内核帮你监控了,应用程序只需要处理那些内核通知你的IO句柄即可,这种机制的前提是即使建立数万连接,某时刻可读写的fd数量只占总连接量的很小的比例,因此借助于内核事件驱动机制,就可以实现单线程的数万Socket的管理。
举个栗子:
一个大工厂很多车间,之前必须每个车间有个值班人员,per house per woker的模式,大部分情况下车间是没有异常情况的,但是为了保证万无一失,仍然需要一名工作人员。
后来引入了监控报警系统,视频音频等信息都实时传输到中控室,从而1名或数名工作人员就可以完成整个厂区的监控,大大提高效率。
IO复用就不多说了,并没有什么太多复杂之处,目前热门的epoll就是其中的悍将,至于epoll的一些详细的机制可以自行查询不再赘述了。

2.事件处理模型

网络设计模式中,如何处理各种I/O事件是其非常重要的一部分,Reactor 和Proactor两种事件处理模型应运而生,可以使用同步I/O实现Reactor模型,使用异步I/O实现Proactor模型。


  • Reactor事件处理模型

Reactor模型是同步I/O事件处理的一种常见模型,其核心思想:将关注的I/O事件注册到多路复用器上,一旦有I/O事件触发,将事件分发到事件处理器中,执行就绪I/O事件对应的处理函数中。
模型中有三个重要的组件:
  • 多路复用器:由操作系统提供接口,Linux提供的I/O复用接口有select、poll、epoll

  • 事件分离器:将多路复用器返回的就绪事件分发到事件处理器中

  • 事件处理器:处理就绪事件处理函数


典型的Reactor模型类图结构:

Reactor 类结构中包含有的主要角色:
  • Handle:标示文件描述符

  • Event Demultiplexer:对操作系统内核实现I/O复用接口的封装等待发生事件发生

  • Event Handler:事件处理接口

  • Event Handler A/B:实现应用程序所提供的特定事件处理逻辑

  • Reactor:反应器定义一个接口,注册和删除关注的事件句柄、运行事件处理循环、等待就绪事件触发,分发事件到注册的回调函数。


Reactor模型工作的简化流程:


  • Proactor事件处理模型

与Reactor不同的是,Proactor使用异步I/O系统接口将I/O操作托管给操作系统,Proactor模型中分发处理异步I/O完成事件,并调用相应的事件处理接口来处理业务逻辑。
Proactor类结构如图所示:

Proactor类结构中包含如下角色:
  • Handle:socket句柄;

  • Async Operation Processor:异步操作处理器执行异步操作,一般由内核实现

  • Async Operation:异步操作

  • Completion Event Queue:完成事件队列

  • Proactor:主动器 为应用程序进程提供事件循环,从完成事件队列中取出异步操作的结果,分发调用相应的后续处理逻辑

  • Completion Handler:完成事件接口,一般由回调函数组成

  • Completion Handler A/B:实现接口定义特定的应用处理逻辑。


Proactor模型的简化的工作流程:

Proactor利用异步I/O并行能力带来更高的效率,但同时增加了编程复杂度。windows对异步I/O提供了很好的支持,而Linux对异步I/O操作支持并不是特别理想,因此Linux平台上还是以Reactor模型为主,Boost asio采用的是Proactor模型。


3.并发模式

在I/O密集型的程序,采用并发方式可以提高CPU的使用率,可采用多进程和多线程两种方式实现并发。
其中包括半同步/半异步模式、半同步/半反应堆模式、半同步/反应堆模式改进版、Follower/Leader模式。

  • 同步和异步概念

并发模式中的同步异步和 I/O模型中的同步异步并不一样:
  • 并发模式中同步指程序按照代码顺序执行,异步指程序依赖事件驱动

  • I/O模型中同步异步用来区分是主动读取数据结构,还是内核帮忙完成数据的读取再返回给线程


  • 半同步/半异步HAHS模式

半异步/半同步模式Half-Sync/Half-Async简称HSHA,是说这个网络模型中异步和同步都存在,IO层是异步处理,业务处理是同步,因此需要依赖于内核的异步IO机制。
HSHA模式工作流程如图:

  • 异步线程监听到事件后,由内核完成读取数据,异步将其封装为请求对象插入到请求队列中

  • 请求队列有新的请求对象,通知同步线程获取请求对象,这个对象是包含了数据的结构,并不是fd

  • 同步线程处理请求对象,实现业务逻辑

综上可知当客户端发送请求时,服务端接收数据是异步的,工作线程从队列收到数据之后是同步的,所以称为半同步/半异步。


  • 半同步/半反应堆HSHR模式

由于HAHS模式依赖于内核的异步IO支持,Linux本身AIO并不理想,因此可以借助于epoll等IO多路复用来模拟这个过程,但是本质上epoll仍然是同步的,因为连接的数据仍然需要自己来读取,因此epoll返回的只是活跃的fd。
半同步/半反应堆模式Half-Sync/Half-Reactor简称HSHR,和HAHS模式很类似,区别在于IO层使用epoll多路复用并非纯异步IO实现,数据处理线程和IO线程之间仍然通过队列来实现数据传输,但是相比HSHA来说,HSHR模式传输的是活跃fd而不是读取的数据。

虽然HSHR模式克服了对纯异步IO的依赖,但是基础版本的HSHR模式,IO线程完成连接的到达处理和响应处理,也就是同时监听新连接和已建立的连接,并且基于队列与后面的工作线程传输数据,在非常高的并发场景可能存在瓶颈,因此后续有对此的改进版本。


  • 半同步/半反应堆模式的改进版

HSHR模式中单一IO线程既要处理新连接又要监控已连接fd的读写事件,因此改进版本增加从线程进行已连接fd的读写事件监听,原来的IO主线程只负责处理新连接,然后将建立的fd扔给从线程进行监听读写事件。
有的地方也称之为主从Reactor模式,如图:

其工作流程为:
  • 主线程实现连接监听,只处理网络I/O连接事件

  • 新的连接fd分发至工作线程中,这些fd上的I/O事件都由该工作线程处理,工作线程都可以处理多个fd的读写事件

  • 工作线程独立维护自己的事件循环,监听不同连接fd的I/O事件

  • 处理任务可以使用线程池或者从线程自己处理


  • 领导者/追随者LF模式

Follower/Leader模式是多个工作线程轮流进行事件监听、事件分发、处理事件的模式。任何一个时间点,只有一个工作线程处理成为Leader负责I/O事件监听,而其他线程都是Follower,并等待成为Leader。
Follower/Leader模式的工作流概述如下:
  • 当前Leader Thread监听到就绪事件后,从Follower 线程集中推选出 空闲Thread成为新的Leader

  • 新的Leader Thread继续I/O监听

  • 之后继续处理I/O就绪事件,执行完后加入到Follower 线程集中,等待成为Leader

从上描述,Leader/Follower模式的工作线程存在三种状态,工作线程同一时间只能处于一种状态,这三种状态为:
  • Leader:线程处于领导者状态,负责监听I/O事件;

  • Processing:线程处理就绪I/O事件;

  • Follower:等待成为新的领导者或者可能被当前Leader指定处理就绪事件。


4.Memcache网络模型分析

Memcached采用了很典型的Master-Worker模型,采用的是多线程而不是多进程. 主线程Master接收连接, 然后把连接分派给工作线程Worker,工作线程处理业务逻辑。

核心的共享数据是消息队列,主线程会把收到的事件请求放入队列,随后调度程序会选择一个空闲的Worker线程来从队列中取出事件请求进行处理Memcached使用libevent实现事件循环,如图:


5.参考资料

  • https://tech.youzan.com/yi-bu-wang-luo-mo-xing/

  • https://zhuanlan.zhihu.com/p/58860015

  • http://xiaobaoqiu.github.io/blog/2014/11/03/memcachedwang-luo-mo-xing/

  • 《Linux高性能服务器编程》游双

6.往期精彩

浅析Redis 4.0新特性之LazyFree
理解Redis持久化
Linux中的各种锁及其基本原理
浅析CPython的全局解释锁GIL
浅谈Linux下Socket选项设置
深入理解IO复用之epoll
理解Redis的反应堆模式


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存