nginx处理请求的十一阶段分析

nginx处理请求流程

nginx启动时master进程加载配置文件,根据配置文件初始化监听的socket,fork worker进程。
worker进程与client建立socket连接处理请求,接收请求读取请求行、请求头、请求体。
处理请求,根据处理结果响应请求,响应行/头/体。

对应函数处理流程如下:

ngx_http_add_listening ---> ngx_http_init_connection --->
ngx_http_wait_request_handler ---> ngx_http_process_request_line --->
ngx_http_process_request_headers ---> ngx_http_process_request --->
ngx_http_handler ---> ngx_http_core_run_phases

nginx大部分event采用epoll EPOLLET边沿触发的方法来触发事件,只有listen端口的读事件是EPOLLLT水平触发。对于边沿触发,如果出现了可读事件,必须及时处理,否则可能会出现读事件不再触发,连接饿死的情况。

由此可见worker进程在处理完request_line和request_headers之后。
会进入ngx_http_core_module.c文件的phase入口函数:ngx_http_core_run_phases()
这就进入了著名的nginx处理请求十一个函数阶段。

十一个阶段,每个阶段有各自的checker和handler
通过cheker函数来判断是继续在本阶段handler,还是去下一个phase的handler处理。
或者跳到某个阶段handler处理。

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,
 
    NGX_HTTP_SERVER_REWRITE_PHASE,
 
    NGX_HTTP_FIND_CONFIG_PHASE,
    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,
 
    NGX_HTTP_PREACCESS_PHASE,
 
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,
 
    NGX_HTTP_TRY_FILES_PHASE,
    NGX_HTTP_CONTENT_PHASE,
 
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;


ngx_http_core_run_phases执行十一阶段handler

遍历各个阶段的checker和handler 如果返回结果为NGX_AGAIN交由下一个phase处理,OK则返回。

void ngx_http_core_run_phases(ngx_http_request_t *r)
{
    ngx_int_t                   rc;
    ngx_http_phase_handler_t   *ph;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    // ph为指向 ngx_http_phase_handler_t 结构的指针,存储了各phase的checker和handler。
    ph = cmcf->phase_engine.handlers;

    // while顺序执行checker
    // 根据checker指引,handler处理根据处理结果进行下一步走向
    while (ph[r->phase_handler].checker) {

        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

        if (rc == NGX_OK) {
            return;
        }
    }
}

十一阶段的handler是如何添加的

各个phase的handler 添加到ngx_http_core_module的cmcf->phase_engine.handlers数组中。
使用 ngx_http_phase_t 结构存储每个阶段可用的处理函数(handler),它实际上是动态数组 ngx_array_t,元素类型为 ngx_http_handler_pt,存储在ngx_http_core_main_conf_t中。
所以cmcf结构为ngx_http_core_main_conf_t。

参考文章:nginx phase handler处理及log phase处理_晓镁的博客-CSDN博客

ngx_http_block() 函数会调用所有模块的 postconfiguration 函数把自己的 handler 处理函数添加到 phases 数组里。

随后 nginx 执行函数 ngx_http_init_phase_handlers(),该函数会遍历 phases 数组,计算 handler 模块的数量,统计所以已经注册的 handler 数量并分配内存,再安阶段分类,把每个 handler 与对应阶段的 checker 组合起来,填入引擎数组。

for (m = 0; ngx_modules[m]; m++) {
        ...
        if (module->postconfiguration) {
            if (module->postconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }
    ...
    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

编译nginx模块的handler

例如编译nginx时 enable ngx_http_geoip_module

找到对应的模块代码文件,找到ngx_module_t ngx_http_geoip_module
 

ngx_module_t  ngx_http_geoip_module = {
    NGX_MODULE_V1,
    &ngx_http_geoip_module_ctx,            /* module context */
    ngx_http_geoip_commands,               /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

通过module context 找到 ngx_http_geoip_module_ctx 又找到 preconfiguration 为 ngx_http_geoip_add_variables,ngx_http_geoip_add_variables就是handler函数。

static ngx_http_module_t  ngx_http_geoip_module_ctx = {
    ngx_http_geoip_add_variables,          /* preconfiguration */
    NULL,                                  /* postconfiguration */

    ngx_http_geoip_create_conf,            /* create main configuration */
    ngx_http_geoip_init_conf,              /* init main configuration */

    NULL,                                  /* create server configuration */
    NULL,                                  /* merge server configuration */

    NULL,                                  /* create location configuration */
    NULL                                   /* merge location configuration */
};

模块编译部分后面再详细说明。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值