nginx系列之九:lua服务

前言

nginx系列之一:nginx入门
nginx系列之二:配置文件解读
nginx系列之三:日志配置
nginx系列之四:web服务器
nginx系列之五: 负载均衡
nginx系列之六:cache服务
nginx系列之七:限流配置
nginx系列之八:使用upsync模块实现负载均衡
nginx系列之九:lua服务

一、nginx请求处理流程

1.1 nginx 11 个处理阶段

nginx实际把http请求处理流程划分为了11个阶段,这样划分的原因是将请求的执行逻辑细分,以模块为单位进行处理,各个阶段可以包含任意多个HTTP模块并以流水线的方式处理请求。这样做的好处是使处理过程更加灵活、降低耦合度。这11个HTTP阶段如下所示:

1.1.1 接收到完整的HTTP头部后处理的阶段

NGX_HTTP_POST_READ_PHASE:接收到完整的HTTP头部后处理的阶段,它位于uri重写之前,实际上很少有模块会注册在该阶段,默认的情况下,该阶段被跳过。

1.1.2 URI与location匹配前,修改URI的阶段

NGX_HTTP_SERVER_REWRITE_PHASE:URI与location匹配前,修改URI的阶段,用于重定向,也就是该阶段执行处于server块内,location块外的重写指令,在读取请求头的过程中nginx会根据host及端口找到对应的虚拟主机配置。

1.1.3. 根据URI寻找匹配的location块配置项阶段

NGX_HTTP_FIND_CONFIG_PHASE:根据URI寻找匹配的location块配置项阶段,该阶段使用重写之后的uri来查找对应的location,值得注意的是该阶段可能会被执行多次,因为也可能有location级别的重写指令。

1.1.4 上一阶段找到location块后再修改URI,location级别的uri重写阶段

NGX_HTTP_REWRITE_PHASE:上一阶段找到location块后再修改URI,location级别的uri重写阶段,该阶段执行location基本的重写指令,也可能会被执行多次。

1.1.5 防止重写URL后导致的死循环,location级别重写的后一阶段

NGX_HTTP_POST_REWRITE_PHASE:防止重写URL后导致的死循环,location级别重写的后一阶段,用来检查上阶段是否有uri重写,并根据结果跳转到合适的阶段。

1.1.6 该阶段在权限控制阶段之前,一般也用于访问控制

NGX_HTTP_PREACCESS_PHASE:下一阶段之前的准备,访问权限控制的前一阶段,该阶段在权限控制阶段之前,一般也用于访问控制,比如限制访问频率,链接数等。

1.1.7 访问权限控制阶段

NGX_HTTP_ACCESS_PHASE:让HTTP模块判断是否允许这个请求进入Nginx服务器,访问权限控制阶段,比如基于ip黑白名单的权限控制,基于用户名密码的权限控制等。

1.1.8 访问权限控制的应答阶段

NGX_HTTP_POST_ACCESS_PHASE:访问权限控制的后一阶段,该阶段根据权限控制阶段的执行结果进行相应处理,向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝。

1.1.9 访问静态文件资源阶段

NGX_HTTP_TRY_FILES_PHASE:为访问静态文件资源而设置,try_files指令的处理阶段,如果没有配置try_files指令,则该阶段被跳过。

1.1.10 处理HTTP请求内容的阶段

NGX_HTTP_CONTENT_PHASE:处理HTTP请求内容的阶段,大部分HTTP模块介入这个阶段,内容生成阶段,该阶段产生响应,并发送到客户端。

1.1.11 处理完请求后的日志记录阶段

NGX_HTTP_LOG_PHASE:处理完请求后的日志记录阶段,该阶段记录访问日志。

1.2 以上11个阶段中,HTTP无法介入的阶段有4个:

  • NGX_HTTP_FIND_CONFIG_PHASE
  • NGX_HTTP_POST_REWRITE_PHASE
  • NGX_HTTP_POST_ACCESS_PHASE
  • NGX_HTTP_TRY_FILES_PHASE

剩余的7个阶段,HTTP模块均能介入,每个阶段可介入模块的个数也是没有限制的,多个HTTP模块可同时介入同一阶段并作用于同一请求。

HTTP阶段的定义,包括checker检查方法和handler处理方法,如下所示

typedef structngx_http_phase_handler_s ngx_http_phase_handler_t;
/*一个HTTP处理阶段中的checker检查方法,仅可以由HTTP框架实现,以此控制HTTP请求的处理流程*/
typedef ngx_int_t(*ngx_http_phase_handler_pt)(ngx_http_request_t *r, ngx_http_phase_handler_t*ph);
/*由HTTP模块实现的handler处理方法*/
typedef ngx_int_t(*ngx_http_handler_pt)(ngx_http_request_t *r);

struct ngx_http_phase_handler_s {    
  	/*在处理到某一个HTTP阶段时,HTTP框架将会在checker方法已实现的前提下首先调用checker方法来处理请求,
    而不会直接调用任何阶段中的hanlder方法,只有在checker方法中才会去调用handler方法,因此,事实上所有
    的checker方法都是由框架中的ngx_http_core_module模块实现的,且普通模块无法重定义checker方法*/
    ngx_http_phase_handler_pt  checker;    /*除ngx_http_core_module模块以外的HTTP模块,只能通过定义handler方法才能介入某一个HTTP处理阶段以处理请求*/
    ngx_http_handler_pt        handler;    /*将要处理的下一个HTTP处理阶段的序号
    next的设计使得处理阶段不必按顺序依次执行,既可以向后跳跃数个阶段继续执行,也可以跳跃到之前的某个阶段重新
    执行,通常,next表示下一个处理阶段中的第1个ngx_http_phase_handler_t处理方法*/
    ngx_uint_t                 next;
};

一个http{}块解析完毕后,将会根据nginx.conf中的配置产生由ngx_http_phase_handler_t组成的数组,在处理HTTP请求时,一般情况下这些阶段是顺序向后执行的,但ngx_http_phase_handler_t中的next成员使得它们也可以非顺序地执行,ngx_http_phase_engine_t结构体就是所有ngx_http_phase_handler_t组成的数组,如下所示:

typedef struct {    
  /*handlers是由ngx_http_phase_handler_t构成的数组首地址,它表示一个请求可能经历的所有ngx_http_handler_pt处理方法*/
    ngx_http_phase_handler_t  *handlers;    
  /*表示NGX_HTTP_SERVER_REWRITE_PHASE阶段第1个ngx_http_phase_handler_t处理方法在handlers数组中的序号,用于在执行HTTP请求的任何阶段中快速跳转到HTTP_SERVER_REWRITE_PHASE阶段处理请求*/
    ngx_uint_t                 server_rewrite_index;    
  /*表示NGX_HTTP_PREACCESS_PHASE阶段第1个ngx_http_phase_handler_t处理方法在handlers数组中的序号,用于在执行HTTP请求的任何阶段中快速跳转到NGX_HTTP_PREACCESS_PHASE阶段处理请求*/
    ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;

可以看到,ngx_http_phase_engine_t中保存了在当前nginx.conf配置下,一个用户请求可能经历的所有ngx_http_handler_pt处理方法,这是所有HTTP模块可以合作处理用户请求的关键,这个ngx_http_phase_engine_t结构体保存在全局的ngx_http_core_main_conf_t结构体中,如下:

typedef struct {
    ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */
    /*由下面各阶段处理方法构成的phases数组构建的阶段引擎才是流水式处理HTTP请求的实际数据结构*/
    ngx_http_phase_engine_t    phase_engine;
    ngx_hash_t                 headers_in_hash;
    ngx_hash_t                 variables_hash;
    ngx_array_t                variables;       /* ngx_http_variable_t */
    ngx_uint_t                 ncaptures;
    ngx_uint_t                 server_names_hash_max_size;
    ngx_uint_t                 server_names_hash_bucket_size;
    ngx_uint_t                 variables_hash_max_size;
    ngx_uint_t                 variables_hash_bucket_size;
    ngx_hash_keys_arrays_t    *variables_keys;
    ngx_array_t               *ports;
    ngx_uint_t                 try_files;       /* unsigned  try_files:1 */
    /*用于在HTTP框架初始化时帮助各个HTTP模块在任意阶段中添加HTTP处理方法,它是一个有11个成员的ngx_http_phase_t数组,
    其中每一个ngx_http_phase_t结构体对应一个HTTP阶段,在HTTP框架初始化完毕后,运行过程中的phases数组是无用的*/
    ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;

在ngx_http_phase_t中关于HTTP阶段有两个成员:phase_engine和phases,其中phase_engine控制运行过程中的一个HTTP请求所要经过的HTTP处理阶段,它将配合ngx_http_request_t结构体中的phase_handler成员使用(phase_handler制定了当前请求应当执行哪一个HTTP阶段);而phases数组更像一个临时变量,它实际上仅会在Nginx启动过程中用到,它的唯一使命是按照11个阶段的概率初始化phase_engine中的handlers数组。

typedef struct {    
  /*handlers动态数组保存着每一个HTTP模块初始化时添加到当前阶段的处理方法*/
    ngx_array_t                handlers;
} ngx_http_phase_t;

在HTTP框架的初始化过程中,任何HTTP模块都可以在ngx_http_module_t接口的postconfiguration方法中将自定义的方法添加到handler动态数组中,这样,这个方法就会最终添加到phase_engine动态数组中。

二、nginx lua 8个阶段

2.1 lua的处理流程

init_by_lua                         http
set_by_lua                         server, server if, location, location if
rewrite_by_lua                   http, server, location, location if
access_by_lua                    http, server, location, location if
content_by_lua                  location, location if
header_filter_by_lua          http, server, location, location if
body_filter_by_lua             http, server, location, location if
log_by_lua                         http, server, location, location if

2.2 lua的处理流程详解

2.2.1 初始化

init_by_lua:在nginx重新加载配置文件时,运行里面lua脚本,常用于全局变量的申请。(例如:lua_shared_dict共享内存的申请,只有当nginx重起后,共享内存数据才清空,这常用于统计。)

2.2.2 流程分支处理判断变量初始化

set_by_lua:流程分支处理判断变量初始化(设置一个变量,常用与计算一个逻辑,然后返回结果,该阶段不能运行Output API、Control API、Subrequest API、Cosocket API)

2.2.3 转发、重定向、缓存等功能

rewrite_by_lua:转发、重定向、缓存等功能 (例如特定请求代理到外网,在access阶段前运行,主要用于rewrite)

2.2.4 IP准入、接口权限等情况集中处理

access_by_lua:IP准入、接口权限等情况集中处理(例如配合iptable完成简单防火墙,主要用于访问控制,能收集到大部分变量,类似status需要在log阶段才有。这条指令运行于nginx access阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。)

2.2.5 内容生成

content_by_lua:内容生成,阶段是所有请求处理阶段中最为重要的一个,运行在这个阶段的配置指令一般都肩负着生成内容(content)并输出HTTP响应。

2.2.6 应答HTTP过滤处理

header_filter_by_lua:应答HTTP过滤处理,一般只用于设置Cookie和Headers等,该阶段不能运行Output API、Control API、Subrequest API、Cosocket API(例如添加头部信息)。

2.2.7 应答BODY过滤处理

body_filter_by_lua:应答BODY过滤处理(例如完成应答内容统一成大写)(一般会在一次请求中被调用多次, 因为这是实现基于 HTTP 1.1 chunked 编码的所谓“流式输出”的,该阶段不能运行Output API、Control API、Subrequest API、Cosocket API)

2.2.8 会话完成后本地异步完成日志记录

log_by_lua:会话完成后本地异步完成日志记录(日志可以记录在本地,还可以同步到其他机器)(该阶段总是运行在请求结束的时候,用于请求的后续操作,如在共享内存中进行统计数据,如果要高精确的数据统计,应该使用body_filter_by_lua,该阶段不能运行Output API、Control API、Subrequest API、Cosocket API)

三、nginx和lua运行阶段的对应关系

1)init_by_lua,运行在initialization Phase;
2)set_by_lua,运行在rewrite 阶段;
​ set 指令来自 ngx_rewrite 模块,运行于 rewrite 阶段;
3)rewrite_by_lua 指令来自 ngx_lua 模块,运行于 rewrite 阶段的末尾
4)access_by_lua 指令同样来自 ngx_lua 模块,运行于 access 阶段的末尾;
​ deny 指令来自 ngx_access 模块,运行于 access 阶段;
5)content_by_lua 指令来自 ngx_lua 模块,运行于 content 阶段;不要将它和其它的内容处理指令在同一个location内使用如proxy_pass;
​ echo 指令则来自 ngx_echo 模块,运行在 content 阶段;
6)header_filter_by_lua 运行于 content 阶段,output-header-filter 一般用来设置cookie和headers;
7)body_filter_by_lua,运行于 content 阶段;
8)log_by_lua,运行在Log Phase 阶段;

如图:
在这里插入图片描述

参考资料:

1.https://blog.csdn.net/fb408487792/article/details/53610140

2.https://blog.csdn.net/lijinqi1987/article/details/53010000?locationNum=15&fps=1

3.https://blog.csdn.net/yangguanghaozi/article/details/54139258

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值