1. Home
  2. nginx专版
  3. openresty+lua

1. ngnix lua开发专版:ngx_lua运行机制的分析(lua是如何嵌入到nginx请求处理流程里面的)

主要分析流程

  1. ngnix特点
  2. ngx_lua的特点分析
  3. nginx的http请求流程分析
  4. 基于nginx流程的ngx_lua生命周期分析

1. nginx特点

nginx是模块化的结构,每个模块之间并没有强耦合,这也方便了开发者对其进行定制化开发,但是如果我们用c和c++去开发nginx内嵌的程序,我们需要符合 Nginx 的开发规则和数据结构使用,而且需要我们熟悉Nginx源码,再加上调试的复杂度,会极大影响我们的开发周期与效率

1. ngx_lua的特点分析

ngx_lua属于openresty的内部模块,通过这个模块将lua内嵌如nginx的结构中。Lua内建协程,通过协程的挂起与唤醒可以很好的通过回调函数的形式把异步的调用同步化,我们都知道nginx的高性能取决于全异步的调用方式,lua就可以通过协程的方式调用异步的api从而使使用者可以用同步编程的方式编写高性能的异步程序,而且并不影响nginx本身的性能。

ngx_lua把耗时且阻塞的I/O操作都委托给 Nginx 事件模型,从而实现完全的非阻塞调用 协程在挂起时自动保存上下文,工作进程上的 VM 可以处理下一个协程的任务层事件模型完成任务时,根据回调,对应的例程会被恢复上下文,从而继续执行用户操作,这个过程不需要对数据进行同步和匹配,用起来与同步操作无异。

nginx工作模式是管理进程(master process) + 工作进程(worker processes)的模式,我们可以称之为看门狗模式

下面是nginx的看门狗工作模式
file

对于ngx_lua,我们可以理解为在以上这种基础模式的情况下,加入了lua解释器和lua虚拟机,相当于每个工作进程都有自己独立的lua解释器和虚拟机实例,而且单独工作进程所处理的请求都会共享这个实例。ngx_lua处理请求的方式是“一个请求对应一个协程”,当请求被建立的时候,对应的协程也会被创建出来,当请求完成的时候,这个对应的协程也会被销毁。同时每个协程都有自己的独立全局变量空间,所以请求跟请求之间的协程不会有相互影响,而且代码也会被放入到sandbox沙箱里面,请求创建的时候协程全局变量以及代码sandbox所对应的内存空间都会被创建,请求结束的时候这些内存空间会相应被销毁。

这时候有人可能会担心请求量大,协程数量也随之增大,起对应的内存空间也会增大,那么会不会影响整体系统的性能呢?

duck不必担心这个问题,协程是轻量级线程,而且ngx_lua本身给每个协程分配的内存空间在2kb左右,对于系统性能消耗大家不必太担心的。
下面是ngx_lua与nginx本身配合的整体生命周期
file

整体流程:

a. worker process初始化ngnix各个模块
b. event模块检查到有用户请求,然后创建连接
c. 根据nginx配置和请求细节调用对应的handler(假设有ngx_lua的配置),然后调用对应的ngx_lua
d. ngx_lua模块调用lua VM,运行对应的代码
e. lua VM 调用lua代码
f. VM 返回结果给ngx_lua
g. ngx_lua给http模块返回响应数据
h. http接收到数据后向event模块发出响应
i. event模块向工作进程交出控制权

ngx_lua整体机制:

a. 每个工作进程创建对应的lua虚拟机
b. ngnix i/o操作封装为lua使用的api载入虚拟机给我们写的lua代码使用
c. 每个请求都会拉起一个对应的协程进行处理,且协程与协程之间数据是不会相互污染的
d. Lua代码调用i/o等异步接口时,当前协程会被挂起,上下文数据自动保存,不会阻塞工作进程
e. i/O 等异步操作完成时还原线程上下文,继续代码执行

3.nginx的http请求阶段分析

首先看一个结构体:

typedefenum{

NGX_HTTP_POST_READ_PHASE = 0, // 接收到完整的HTTP头部后处理的阶段

NGX_HTTP_SERVER_REWRITE_PHASE, // URI与location匹配前,修改URI的阶段,用于重定向

NGX_HTTP_FIND_CONFIG_PHASE, // 根据URI寻找匹配的location块配置项

NGX_HTTP_REWRITE_PHASE, // 上一阶段找到location块后再修改URI

NGX_HTTP_POST_REWRITE_PHASE, // 防止重写URL后导致的死循环

NGX_HTTP_PREACCESS_PHASE, // 下一阶段之前的准备

NGX_HTTP_ACCESS_PHASE, // 让HTTP模块判断是否允许这个请求进入Nginx服务器

NGX_HTTP_POST_ACCESS_PHASE, // 向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝

NGX_HTTP_TRY_FILES_PHASE, // 为访问静态文件资源而设置

NGX_HTTP_CONTENT_PHASE, // 处理HTTP请求内容的阶段,大部分HTTP模块介入这个阶段

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

} ngx_http_phases;

ngnix将一个http请求分为了11个阶段,这些阶段是按既定顺去去执行的,接下来我们逐一说一下这11个步骤

  1. NGX_HTTP_POST_READ_PHASE 接收到完整的http请求头后的处理阶段
  2. NGX_HTTP_SERVER_REWRITE_PHASE 在将请求的 URI location 表达式匹配前,修改请求的URI(重定向),是一个独立的 HTTP 阶段
  3. NGX_HTTP_FIND_CONFIG_PHASE 根据客户端请求的url去寻找匹配的location表达式
  4. NGX_HTTP_REWRITE_PHASE 在上面的查找location的阶段完成后对当前url进行重写rewrite
  5. NGX_HTTP_POST_REWRITE_PHASE 重写url后 防止错误的配置造成递归修改uri的死循环,默认规定的循环次数为10次超过这个次数会返回500错误
  6. NGX_HTTP_PREACCESS_PHASE 这个阶段(NGX HTTP ACCESS
    PHASE)决定请求的访问权限前, HTTP模块可以介入的处理阶段
  7. NGX_HTTP_ACCESS_PHASE 用于http模块判断是否允许这个请求访问我们的nginx服务器
  8. NGX_HTTP_POST_ACCESS_PHASE 如果上一个阶段请求判断的时候,结果是请求非法,这个阶段是对上个阶段请求非法状况的一个收尾
    负责向用户端返回拒绝服务的错误请求。
  9. NGX_HTTP_TRY_FILES_PHASE 这个阶段是为了try_files的, HTTP求访问静态文件资源时,try files 置项可 以使这个请求顺序地访问多个静态文件资源,果某一次访问失败,则继续访问 try_files 中指定的下个静态资源
  10. NGX_HTTP_CONTENT_PHASE 用于处理http请求的内容阶段,这也是大多是http介入的请求阶段
  11. NGX_HTTP_LOG_PHASE 日志写入阶段 ngx_http_log_module 实际上也是在这里注册了一个handler实现的日志写入工作

4. ngx_lua生命周期

ngx_lua的生命周期是基于nginx本身的11个阶段的,但并不是全部,体现在Rewrite/Access阶段、Content阶段、Log阶段

下面这张流程图是对ngx_lua阶段的详细解释
file

我们逐一看一下每个阶段的作用

  1. init_by_lua/init_by_lua_file (loading-config) (http)
    主要在nginx加载配置文件的时候,初始化全局配置的时候

  2. init_worker_by_lua/init_worker_by_lua_file (starting worker) (http)
    每个worker进程启动的时候调用的计时器,如果管理进程不同意则会在init_by_lua后面执行,通常的作用是用于定时拉去配置/数据或者是进行相应的健康检查

  3. set_by_lua/set_by_lua_file (rewrite) (server,server if, location, location if)
    用来设置nginx变量可以用来实现复杂的赋值逻辑弥补了nginx本身的缺陷

  4. rewrite_by_lua/rewrite_by_lua_file (rewrite tail) (http/server/location/location if)
    rewrite阶段处理可以实现复杂的转发重定向逻辑

  5. access_by_lua/access_by_lua_file (access tail)
    (http/server/location/location if)
    用于访问控制

  6. content_by_lua/content_by_lua_file (content) (location/location if)
    内容处理器,接收到请求内容并做相应处理后返回

  7. header_filter_by_lua/header_filter_by_lua_file (output_header_filter) (http/server/location/location if)
    设置header和cookie

  8. body_filter_by_lua/body_filter_by_lua_file (output_body_filter) (http/server/location/location if)
    对响应数据进行过滤

  9. log_by_lua/log_by_lua_file/balancer_by_lua_block/balancer_by_lua_file/ssl_certificate_by_lua_block
    (log/content/content) (http/server/location/location if/upstream/server)
    a.log阶段处理,如记录访问量统计平均响应时间
    b.上游服务器中的负载均衡算法
    c.在ngnix的下游服务开始一个ssl握手操作时将运行本配置项的lua代码

原创文章,作者:admin,如若转载,请注明出处:https://www.cxylaowang.com/206.html

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact Us

在线咨询:点击这里给我发消息

邮件:814489173@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code