前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx event框架总结

nginx event框架总结

原创
作者头像
mariolu
修改2019-01-24 13:18:41
3.1K0
修改2019-01-24 13:18:41
举报

一、什么是nginx event框架

Nginx 的 event(事件)处理机制是nginx的核心功能。nginx抽象了event机制,在多个平台有不同的event调用实现方法。比如说经常用的AIO(异步IO),/dev/poll(Solaris 和 Unix 特有),epoll(Linux 特有),kqueue(BSD 特有),poll,select 等。

event 模块的功能就是,监听网络事件和定时器事件。epoll模块对事件进行注册处理接口或者取消订阅关注这类事件。当事件网络IO 可读可写的时候,相应的读写事件handler就会被唤醒,此时就会去处理事件的回调函数。

对于 Linux,Nginx 大部分 event 采用 EPOLLET(边沿触发)的方法来触发事件,只有 listen 端口的读事件是 EPOLLLT(水平触发)。两者的区别是,如果边沿触发出现了可读事件,必须及时处理,否则可能会出现读事件再也不再触发被处理的情况。

二、nginx event框架如何运作

cycle是全局变量,这个cycle是跟event模块挂钩的。全局只有一个,这个变量挂载着nginx所有的连接,read_event和write_event。

图1、connection和读写事件是一一对应的
图1、connection和读写事件是一一对应的

2.1 struct ngx_cycle_s的定义

代码语言:javascript
复制
struct ngx_cycle_s {
 /*  对于poll,rtsig这样的事件模块,会以有效文件句柄数来预先建立这些ngx_connection t结构
体,以加速事件的收集、分发。这时files就会保存所有ngx_connection_t的指针组成的数组,files_n就是指
针的总数,而文件句柄的值用来访问files数组成员 */
    ngx_connection_t        **files; //sizeof(ngx_connection_t *) * cycle->files_n 
    ngx_connection_t         *free_connections;// 可用连接池,与free_connection_n配合使用
    ngx_event_t              *read_events;// 指向当前进程中的所有读事件对象,每个连接分别有一个读写事件
    ngx_event_t              *write_events;// 指向当前进程中的所有写事件对象,每个连接分别有一个读写事件
}

nginx event框架是和connection框架结合在一起的,一个客户端的connetion对应着一个read event和write event。event结构体把该连接对应的操作方法绑定在一起。每一个事件最核心的部分是handler回调方法,它将由每一个事件消费模块实现,以此决定这个事件究竟如何“消费”和data数据结构。data数据结构是handler的参数。一般就是一个connection结构体对象。

2.2 运作机制

nginx不断陷入处理网络和定时器事件的死循环中。worker进程在循环中不断调用ngx_process_events_and _timers函数。

代码语言:javascript
复制
for ( ;; ) {
        ngx_process_events_and_timers(cycle);
}

ngx_process_events_and_timers需要使用互斥锁解决多进程监听同一个端口(accept竞争,惊群问题)。

2.3 accpet连接和处理连接数据处理法则

抢到了 accept 锁的进程跟一般进程稍微不同的是,它被加上了 NGX_POST_EVENTS 标志,也就是说在 ngx_process_events() 函数里面只接受而不处理事件,并accept到新的连接被加入 post_events 的队列里面。直到 ngx_accept_mutex 锁去掉以后才去处理具体的事件。

这里这样做是因为具体的client 连接比较耗时,相对比来说,accept新的连接这个事件更重要,并且 ngx_accept_mutex 是全局锁,在该进程accpet完之后,会尽早是否这个锁,让给别的进程accept。而本进程去处理之前accept到的连接,也就是说,可以尽量减少该进程抢到锁以后,从 accept 开始到结束的时间,以便其他进程继续接收新的连接,提高吞吐量。

三、怎么编程自定义一个event

什么情况需要event。当你有异步读写事件需要 event框架帮你托管(注册/通知事件)。写法如下:

3.1 创建ngx_event_s 结构体

生成一个ngx_event_s 结构体,实现自己的handler函数,和handler的对象data。这个data在nginx通常是ngx_connection_t。如果是操作自己定义的结构体,可以挂在ngx_connection_t->data下面。一个最简的ngixn_event_t结构需要定义handler和data。nginx_event_t用于触发的fd源自connetion的fd。

代码语言:javascript
复制
// 代表事件的结构体
struct ngx_event_s {
    ...
     void *  data;// 事件相关的对象, 通常指向ngx_connection_t连接对象
    ngx_event_handler_pt  handler;  // 核心,事件消费函数,定义如何处理事件
    ...
}; 

3.2 定义一个ngx_connection_s

ngx_connection_s需要承载上一步创建的event,这里要创建两个,分别挂载在read和write下面。这里需要注意,即使不需要某个事件,也要声明这个event结构体。只是把该event结构体的handler函数置为空。

代码语言:javascript
复制
struct
ngx_connection_s {
// 作为空闲连接时, 指向连接池中下一个空闲连接
// 作为非空闲连接时, 其意义由使用连接的模块定义, 例如http模块将data指向一个http请求(ngx_http_request_t)
void * data;     
// 连接对应的读事件
ngx_event_t * read;     
// 连接对应的写事件
ngx_event_t * write;    
 // 连接对应的侦听对象
ngx_listening_t * listening;    
 // 连接的套接字句柄
ngx_socket_t fd;     
... };

3.3 ngx_connection_s和ngx_event_s 建立联系

connetionc有了read和write的nginx_event_t的结构体,就需要调用注册读写事件。

3.4 注册conneciton到event框架

调用ngx_handle_read_event或者ngx_handle_write_event将event事件注册的全局的event框架中。

函数还可以有些flages可以设置NGX_CLOSE_EVENT, 默认一般是0。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是nginx event框架
    • 二、nginx event框架如何运作
      • 2.1 struct ngx_cycle_s的定义
        • 2.2 运作机制
          • 2.3 accpet连接和处理连接数据处理法则
          • 三、怎么编程自定义一个event
            • 3.1 创建ngx_event_s 结构体
              • 3.2 定义一个ngx_connection_s
                • 3.3 ngx_connection_s和ngx_event_s 建立联系
                  • 3.4 注册conneciton到event框架
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档