nginx通过epoll等事件机制来驱动,下面分析下nginx是如何实现与后端upstream的异步连接。
首先分析下:ngx_event_connect_peer
看下这个函数在哪些地方被调用
1 | $grep -rn 'ngx_event_connect_peer' src/ |
暂时只关注http,只在upstream模块中被调用,看下其使用方法:
调用链: ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
-> rc = ngx_event_connect_peer(&u->peer);
下面分析ngx_event_connect_peer(ngx_peer_connection_t *pc)
1 | struct ngx_peer_connection_s { |
这是专门用来给后端用的connection结构体,
======================================================
在看多了代码后,有这样一个体会:即搞清楚ngx_http_request, ngx_connection_t,ngx_event_t ngx_http_upstream_t等结构体的相互的联动以及为何要这样设计联动,就可以大体上掌握nginx的http框架了、事件框架了
(由于http框架是建立在事件框架基础上的,在对比下mail等七层的框架,就可以很容易融会贯通了。)
r、c、ev间的关系:
知道r如何找其他两者
c = r->connection
rev = c->read;
wev = c->write;
知道c如何找其他两者
r = c->data;(在空闲的c中,c->data指向下一个空闲的c)
rev = c->read;
wev = c->write;
知道到ev如何找其他两者
c = ev->data;
r = c->data;
分析下,为何ev->data指向的是c:因为事件是和连接层面相关的,和七层应用层面无关,事件的data将指向该事件是发生在哪个连接上的。
为何c->data指向r,其实c的data不一定指向r,只是在http层面, c是用于http传输的,那么c的data指向r,如果是在mail传输,c的data指向的是s(ngx_mail_session_t),
为何r->connection会指向c,显而易见从名字就可以看出,且这个c是和客户端的c,不是和上有的c(如果有的化)
和上有的的c是这样:u=r->upstream, c = u->peer.connection(这个c是和上游的c)
对事件的处理的一点心得:
r->read_event_handler/r->write_event_handler为何要有这样的钩子,通过源码可以查看到是在
ngx_http_request_handler(ev)中被调用的:
1 | static void |
而ngx_http_request_handler又被赋为
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;
连接的读写事件的handler
从这里可以看出:事件触发 -> 调用ngx_http_request_handler -> 继续调用r->read_event_handler or r->write_event_handler。
这样nginx提供了这样一种机制:它将ev的回掉设置固定,但是将真正执行的handler留给模块自己去决定,比如
你只需关注在模块中将r->read_event_handler/write_event_handler设置好就OK,不用去设置ev的回调,这算是提供的一种对外接口。