2.2.2 OpenResty入门

OpenResty 将 Lua 语言解释器嵌入到 NGINX 中,从而赋予了NGINX更多拓展的可能。另外,OpenResty 还自带了一些常用的模块,如用于数据库连接的 lua-resty-mysqllua-resty-redislua-resty-memcached等。

1.配置指令拓展

OpenResty 为 NGINX 配置拓展了若干指令,这些指令是使用 OpenResty 进行网关开发的关键,熟悉它们十分必要,常用的指令如下所示。

  • init_by_lua*

init_by_lua* 包含 init_by_luainit_by_lua_blockinit_by_lua_file 三个指令,这三个指令的作用是一样的,但是用法不同。

init_by_luainit_by_lua_block直接在配置文件中编写 Lua 代码,init_by_lua_file 配置Lua代码文件的路径。

OpenResty 的指令往往都包含 *_by_lua*_by_lua_block*_by_lua_file三种形式,使用 *_by_lua_file 形式的指令可以更好地实现配置和代码分离,以下我们都以 *_lua_file 为例进行说明。

语法:init_by_lua_file

上下文:http

指令执行阶段:加载配置时

该指令指定NGINX加载配置时需要执行的Lua代码,通常这个阶段加载常用Lua模块。

// nginx.conf
http {
    init_by_lua_file '/path/to/init.lua';
}

// /path/to/init.lua
-- 加载 cjson 模块
-- cjson 模块用于JSON处理
require "cjson"

一些开发者习惯在 init_by_lua* 阶段定义全局变量,比如 Orange(一个基于OpenResty的网关软件) 和 APACHE APISIX 是这样使用的:

但是,这种做法是不推荐的,在 init_by_lua* 阶段定义全局变量,其作用无非是在后续使用中,不必 require 而可以直接使用诸如 contextapisix 之类的变量。但是这种做法会造成全局命名空间的污染,也可能会造成性能下降。

事实上,在 ngx_lua 上下文中,均需避免使用 Lua 全局变量,官方给出的解释是这样的:

  1. 全局变量的滥用会对并发请求产生不利影响;

  2. 全局变量需要在全局环境中进行 Lua 表查找,开销昂贵;

  3. 全局变量可能造成调试困难;

  • init_worker_by_lua*

语法:init_worker_by_lua_file

上下文:http

指令执行阶段:woker 进程启动时

init_by_lua* 指令是在 NGINX 的主进程启动阶段执行的, 而 init_worker_by_lua* 指令在 worker 进程启动阶段执行。

NGINX 的进程有两类,主进程(master进程)和worker进程,其中主进程只能有一个而worker进程可以有多个。主进程不处理请求,它负责读取和评估配置文件,维护worker进程,而 worker 进程才是真正用于处理请求的。

init_worker_by_lua* 阶段通常用来创建定时器(通过 ngx.timer.atngx.timer.every),用于健康检查或执行定时任务。

  • set_by_lua*

语法:set_by_lua_file $res [$arg1 $arg2 ...]

上下文:server, server if, location, location if

指令执行阶段:rewrite 阶段,用于定义NGINX变量

set_by_lua* 用来定义NGINX变量,NGINX 原生指令 set 可以用来设置变量,如 set $year 2022;,set_by_lua* 进一步拓展了 set 指令,使得变量的值可以通过运行一段Lua代码得出。

  • rewrite_by_lua* 语法:rewrite_by_lua_file

上下文:http, server, location, location if

指令执行阶段:rewrite 阶段结束时

rewrite_by_lua* 是 rewrite 阶段的处理程序,默认在 rewrite 请求处理阶段结束时运行,通常用于检查,改写 URI,实现重定向等。示例如下。

  • access_by_lua*

语法:access_by_lua_file

上下文:http, server, location, location if

指令执行阶段:access 阶段结束时

access_by_lua* 通常用来进行权限检查,安全校验等。

  • content_by_lua*

语法:content_by_lua_block

上下文:location, location if

指令执行阶段:content 阶段

content_by_lua* 为每个请求执行相应的 Lua 代码,当我们把 OpenResty 作为Web服务器时,业务的核心代码就在 content_by_lua* 阶段执行。

  • balancer_by_lua*

语法:balancer_by_lua_file

上下文:upstream

指令执行阶段:content 阶段

balancer_by_lua* 指令是实现动态负载均衡关键。

原生的NGINX使用upstream指令来配置源服务器,当源服务器有更新时,我们必须更新upstream的配置,同时也要reload NGINX。而 balancer_by_lua* 指令实现了源服务器的动态配置,更新源服务器时再也不需要更新NGINX配置文件了,这对于我们开发API网关十分重要。

使用lua-resty-core库中的ngx.balancer模块,我们可以轻松实现动态负载均衡,同时ngx.balancer模块还提供了upstream不具有的功能。利用balancer_by_lua*指令和ngx.balancer模块,我们可以实现灵活的负载均衡策略。

ngx.balancer模块提供了如下常用的静态方法。

方法
作用

set_current_peer

设置当前使用的源服务器

set_more_tries

设置源服务器连接失败后的重试次数

get_last_failure

获取上次连接失败的详细信息

set_timeouts

设置源服务器的连接和读写超时时间,单位是秒

  • header_filter_by_lua*

语法:header_filter_by_lua_file

上下文:http, server, location, location if

指令执行阶段:output-header-filter

header_filter_by_lua* 指令创建改HTTP响应标头的过滤器。比如,利用header_filter_by_lua*指令可以设置HTTP响应标头。

  • body_filter_by_lua*

语法:body_filter_by_lua_file

上下文:http, server, location, location if

指令执行阶段:output-body-filter

body_filter_by_lua* 指令用于创建HTTP响应体的过滤器。比如,利用 body_filter_by_lua*可以修改响应体的内容。

  • log_by_lua*

语法:log_by_lua_file

上下文:http, server, location, location if

指令执行阶段:log

log_by_lua*指令用于日志收集,它不会代替NGINX的access日志(access.log)。

以上是OpenResty的常用指令,这些指令及其执行的阶段的示意图如下。理解了这张图,也就基本理解了OpenResty的工作过程。

todo 示例图

todo

Last updated