实现百万并发连接的Reactor

作为一个高性能服务器程序通常需要处理三类事件:I/O事件,定时事件及信号。两种高效的事件处理模型:Reactor和Proactor。

Reactor是Linux基于epoll实现的事件模型,Proactor是Windows基于IOCP的异步事件处理。

一、Reactor模型

首先来回想一下普通函数调用的机制:程序调用某函数,函数执行,程序等待,函数将 结果和控制权返回给程序,程序继续处理。Reactor 释义“反应堆”,是一种事件驱动机制。 和普通函数调用的不同之处在于:应用程序不是主动的调用某个 API 完成处理,而是恰恰 相反,Reactor 逆置了事件处理流程,应用程序需要提供相应的接口并注册到 Reactor 上, 如果相应的时间发生,Reactor 将主动调用应用程序注册的接口,这些接口又称为“回调函 数”。

 

 Reactor 模式是处理并发 I/O 比较常见的一种模式,用于同步 I/O,中心思想是将所有要 处理的 I/O 事件注册到一个中心 I/O 多路复用器上,同时主线程/进程阻塞在多路复用器上; 一旦有 I/O 事件到来或是准备就绪(文件描述符或 socket 可读、写),多路复用器返回并将事 先注册的相应 I/O 事件分发到对应的处理器中。

Reactor模型有三个重要的组件:

  • 多路复用器:由操作系统提供,在Linux上一般是select,poll,epoll等系统调用。
  • 事件分发器:将多路复用器中返回的就绪事件分到对应的处理函数中。
  • 事件处理器:复制处理特定事件的处理函数(回调函数)

 

具体流程如下:

  1. 注册读就绪事件和相应的事件处理器;
  2. 事件分离器等待事件;
  3. 事件到来,激活分离器,分离器调用事件对应的处理器;
  4. 事件处理器完成事件的读操作,处理读到的数据,注册新的事件,然后返还控制权。 

Reactor模式是编写高性能网络服务器的技术之一,它具有如下的优点:

  • 响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/多进程的切换开销;
  • 可扩展性,可以方便的通过增加Reactor实例个数了充分利用CPU资源;
  • 可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性

Reactor 模型开发效率上比起直接使用 IO 复用要高,它通常是单线程的,设计目标是 希望单线程使用一颗 CPU 的全部资源,但也有附带优点,即每个事件处理中很多时候可以 不考虑共享资源的互斥访问。可是缺点也是明显的,现在的硬件发展,已经不再遵循摩尔定 律,CPU 的频率受制于材料的限制不再有大的提升,而改为是从核数的增加上提升能力, 当程序需要使用多核资源时,Reactor 模型就会悲剧。

如果程序业务很简单,例如只是简单的访问一些提供了并发访问的服务,就可以直接开 启多个反应堆,每个反应堆对应一颗 CPU 核心,这些反应堆上跑的请求互不相关,这是完 全可以利用多核的。例如 Nginx 这样的 http 静态服务器。

二、Reactor模型设计

1. 结构体设计

复制代码
typedef int NCALLBACK(int, int, void*);  //fd, events, arg=reactor

struct ntyevent {
    int fd;
    int events;
    void* arg;
    int (*callback)(int fd, int events, void* arg);

    int status; //标注该ntyevent是否已经被监测
    char buffer[BUFFER_LENGTH+1]; //缓冲区
    int length;  //缓冲区内数据长度
    long last_active;
};

struct eventblock {
    struct eventblock* next;  //指向下一个eventblock
    struct ntyevent* events; //events数组,长度为 MAX_EPOLL_EVENTS
};

struct ntyreactor {
    int epfd;  
    int blkcnt;  //counts of eventblock
    struct eventblock* evblk;  //
};
复制代码

1.1 struct ntyevent

这是一个事件结构体,它绑定了socket的fd,以及需要监听的事件(events)和事件处理器(callback),还绑定了所属的reactor对象(arg)。

1.2 struct eventblock

这是一个事件块,每一个事件块包含了定长的事件存储数组,以及指向下一个块的指针。

1.3 struct ntyreactor

这是一个reactor结构体,绑定了epoll对象和eventblock空间,并且对eventblock的块数量进行了计数。

在整体设计中,先根据fd找到ntyreactor中对应的ntyevent空间,再设置ntyevent。

2. 函数设置

struct ntyevent* ntyreactor_idx(struct ntyreactor* reactor, int sockfd)

这个函数是根据传入的sockfd,在ntyreactor对象中找到对应的ntyevent空间。

int ntyreactor_alloc(struct ntyreactor* reactor)

这个函数是为ntyreactor申请ntyevent空间,当调用ntyreactor_idx()时,如果fd没有对应的ntyevent空间,会先调用本函数申请到对应的ntyevent空间。ntyreactor_alloc()申请空间是以eventblock为单位申请的。

void nty_event_set(struct ntyevent* ev, int fd, NCALLBACK *callback, void* arg)

这个函数是去设置ntyevent空间的。

int nty_event_add(int epfd, int events, struct ntyevent* ev)

这个函数是设置ntyevent的事件events并将ntyevent纳入epoll对象的监测。

在此函数中,会根据ntyevent对象的status状态判断,是调用EPOLL_CTL_ADD还是EPOLL_CTL_MOD。

int nty_event_del(int epfd, struct ntyevent* ev)

这个函数取消对ntyevent的事件检测。

int recv_cb(int fd, int events, void* arg)

这是接收数据事件的回调函数

int send_cb(int fd, int events, void* arg)

这是发送数据的回调函数

int accept_cb(int fd, int events, void* arg)

这是listenfd的回调函数。在此函数中,会将创建的连接的socket设置为非阻塞状态。

int init_sock(short port)

在此函数中,创建对port端口绑定的服务器listenfd。

int ntyreactor_init(struct ntyreactor* reactor)

这是ntyreactor对象的初始化函数,主要处理申请内存空间。

int ntyreactor_destroy(struct ntyreactor* reactor)

销毁ntyreactor对象中申请的内存空间(eventblock),但不会销毁ntyreactor对象本身。

int ntyreactor_addlistener(struct ntyreactor* reactor, int sockfd, NCALLBACK* acceptor)

将listenfd注册到ntyreactor对象上。

三、Reactor的应用

上面设计的reactor是单线程模式的,除此之外,reactor模式还有多线程和多进程。

1. 单线程Reactor

 

redis使用的就是这种单线程模型,在6.0版本之后支持IO多线程。

 

2. 多线程Reactor

 

多线程的Reactor模型引入线程池的概念,将一些耗时的操作交由新线程执行。

memcached使用的就是多线程的Reactor模型。

3. 多进程Reactor 

 

每个进程都有reactor对象。nginx使用的是多进程的Reactor模型。同时,nginx使用ET模式,因为nginx是做反向代理,做转发数据工作的,不需要界定数据包。

 

-----------------------------------------------------------------------------------------------

github:https://github.com/illusorycat/Reactor_mudel.git

posted @   幻cat  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示