Reactor模型
在Web服务中,处理Web请求时一般有两种体系,一种是多线程并发模式,服务器端每接收客户端的一个请求,就开启一个独立的线程来服务;还有一种是基于事件驱动,定义一系列事件与其对应的响应函数,并将服务器端接受连接与对事件的处理分离。而Reactor模型和Proactor模型便是事件驱动模型的两种实现方式,其中Reactor主要应用于同步I/O模式,而Proactor主要用于异步I/O模式。通过使用这样的模型,能够提高服务器处理I/O的性能,因此掌握它们的用法很有必要。在阅读本文之前,可以提前了解操作系统的I/O复用概念与Redis的基础知识。关于Reactor模型,许多著名的开源项目如Redis都使用了这一模型,接下来就先介绍Reactor是什么,以及在Redis中是如何使用的。
Reactor模型是应对高并发网络I/O请求的一种技术处理方案,主要用于处理客户端和服务器端的交互过程。在这一模型中,有三类事件,简要概括为:
- 连接事件
- 读事件
- 写事件
即客户端与服务器端要建立连接时的连接事件,连接建立后服务器端的读、写事件。通过这三个事件,引出了该模型中的三个重要角色:
- acceptor
- handler
- reactor
它们发挥的作用如下:
- acceptor处理连接事件,在接收连接后,创建handler来处理后续读写事件;
- 在高并发场景下,由于读、写事件可能同时发生,因此需要reactor来负责监听和分配事件。
即有连接请求时,reactor将产生的连接事件交给acceptor处理;有读、写请求时,reactor将读、写事件交由handler处理,如下图所示:
在实现上,根据是单线程还是多线程,Reactor模型又分为3类:
- 单Reactor单线程:accept->read->处理业务逻辑->write都在一个线程中
- 单Reactor多线程:accept/read/write在一个线程中,业务逻辑处理在另一个线程中
- 多Reactor多线程/进程:accept在一个线程/进程,read/write/处理业务逻辑在另一个线程/进程
无论是单线程还是多线程/进程,在实现Reactor模型时,都离不开事件驱动框架。事件处理框架是实现Reactor模型时,需要实现的代码整体控制逻辑,主要包括了两部分:
- 事件初始化
- 事件捕获、分发、处理的主循环
事件初始化指的是在服务器程序启动时,创建需要监听的事件模型,以及该类型对应的handler。而主循环一般使用while循环,在这个循环中,需要捕获发生的事件,判断事件类型,并且根据事件类型来调用handler处理事件,如下图所示:
在Redis中,为了实现事件驱动框架,相应的定义了事件的数据结构、框架的主循环函数、事件捕获分发函数、事件和handler注册函数。
主循环函数是aeMain函数,它实现了一个while循环,只要事件停止循环标志不为true,就会一直在这个主循环中。主循环中调用了aeProcessEvents函数,该函数主要用于事件的捕获与分发,通过查看调用关系能发现,该函数底层是借助操作系统的多路IO复用机制,在Linux下,使用的就是epoll_wait函数来等待事件,并且将准备好的事件返回给aeProcessEvents函数。其调用关系如下图所示:
在aeProcessEvents函数中,根据事件类型不同,将事件交由不同的处理函数处理。
而在主循环之前,针对每个启用的IP端口,都使用使用aeCreateFileEvent函数创建对AE_READABLE事件的监听,并注册其对应的处理函数.
for (j = 0; j < sfd->count; j++) { if (aeCreateFileEvent(server.el, sfd->fd[j], AE_READABLE, accept_handler,NULL) == AE_ERR) { ... }
而aeCreateFileEvent底层实际上是由epoll_ctl函数实现。
Redis的事件驱动框架主要就是这三个函数,首先注册事件及其对应处理函数,随后监听并捕获事件,然后使用handler处理事件。
通过使用Reactor模型,Redis能使用单线程处理高并发的I/O请求,从侧面反映出Reactor模型的优越性。在个人编程项目中,也推荐使用Reactor模型,从而提升I/O请求处理的效率。
主要参考文章:
https://zhuanlan.zhihu.com/p/95662364
极客时间的《Redis源码剖析与实战》课程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了