IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> nginx处理请求的十一阶段分析 -> 正文阅读

[系统运维]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 */
};

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

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 16:08:03  更:2022-05-01 16:10:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 17:52:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码