OpenResty简介

OpenResty是一个基于Nginx和Lua的开源Web开发框架,OpenResty内部集成了大量精良的Lua库、第三方模块和依赖项,可用于搭建高并发、可扩展的Web应用。实际开发中,OpenResty主要用于实现高性能策略网关、防火墙、游戏服务端等要求高性能低延时的场景。不过我们也需要了解,OpenResty并不特别适合于编写业务逻辑,因为它缺乏IDE和调试器的支持。

本系列笔记我们将对OpenResty的原理和使用方法进行介绍。学习OpenResty前,我们需要掌握HTTP协议和Nginx相关的知识,其次还需要了解Lua语言,不过这门语言语法十分简单,花十分钟粗略浏览下文档即可学会基本的使用。

OpenResty项目官网:https://openresty.org/en/

OpenResty的组成

OpenResty的核心包括4个模块:

Nginx:Nginx是一款高性能的Web服务器,它可以理解为OpenResty运行的基础Web框架。

LuaJIT:LuaJIT是支持JIT编译的高性能Lua执行环境,用于执行OpenResty中的Lua脚本代码。

ngx_luangx_lua是Nginx的Lua扩展,允许使用Lua脚本扩展Nginx对HTTP协议的处理功能。

stream_lua:和ngx_lua类似,stream_lua允许Lua脚本扩展Nginx对TCP/UDP协议的处理功能。

围绕这4个核心组件OpenResty还集成了大量扩展,这些扩展主要分为Nginx模块和Lua模块两部分,它们共同构成了整个OpenResty运行时环境。

除了运行时环境,OpenResty还提供了一些开发工具链。

opm:类似NodeJS的NPM,opm是OpenResty的包管理工具,可供我们从官方扩展仓库中安装扩展组件。

resty-cliresty-cli用于以命令行形式执行OpenResty/Lua程序。

restydoc:该命令行工具包含了帮助手册,类似Linux的Man手册。

OpenResty安装

Linux下安装OpenResty

在Linux环境下建议通过源码方式安装OpenResty,我们这里以Ubuntu22.04操作系统为例,介绍如何编译安装OpenResty。

注意:源码包编译后会形成一个自带Nginx和OpenResty框架目录,如果你本身使用过Linux自己的包管理安装过Nginx或OpenResty,注意测试时别和系统的软件包发生冲突。

具体编译前,首先我们需要安装编译器和必要的依赖库。

apt install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make build-essential

前置安装完成后我们还需要下载OpenResty的源码包,源码包可在官网找到。注意我这里使用的是当前版本,你在尝试时可能已经有了新版本,一般来说,我们使用当前最新版本即可。

执行下面命令下载源码包并解压缩。

wget https://openresty.org/download/openresty-1.27.1.1.tar.gz && tar xvf openresty-1.27.1.1.tar.gz

现在我们可以开始编译源码了。使用cd命令进入源码目录,我们需要先使用configure配置编译选项,然后调用Make构建并安装。在配置阶段,--prefix指定的是安装目录,此外还可以使用--with---without-选项来指定开启或关闭编译的模块,这部分具体参考官方文档即可,我们这里将编译模块选项留作默认。

./configure --prefix=/opt/openresty && make && make install

如果一切正常,我们的编译结果就会输出到/opt/openresty目录下。

注:如果我们输出到/opt目录,make install可能需要Root权限。

Windows下安装OpenResty

OpenResty官方提供了Windows操作系统下的预编译包,我们直接将其下载下来使用即可,Windows预编译版本的OpenResty目录结构可能和Linux略有不同,不过具体命令行的操作方式和Linux下类似,这里就不重复介绍了。要注意的是生产环境OpenResty通常都需要在Linux操作系统下运行以提供更好的性能,Windows版本的OpenResty一般仅用于开发和测试用途。

OpenResty软件包目录结构

上一步我们安装完OpenResty后可以查看其目录结构。

/opt/openresty
  |_ bin        # 可执行程序目录
  |_ luajit     # LuaJIT执行环境
  |_ lualib     # Lua相关的组件
  |_ nginx      # Nginx程序目录
  |_ pod        # 参考手册(restydoc)的文档目录
  |_ site       # 包管理器(opm)使用的目录

开发中,我们主要使用的命令就是bin/openresty,它其实是个指向nginx/sbin/nginx的软链接,因此实际上启动OpenResty就是启动Nginx。

编写Hello world程序

接下来我们可以创建一个简单的工程目录来体验OpenResty的使用。OpenResty的工程目录比较简单,其实它可以理解为就是包含Nginx配置文件和若干Lua脚本的文件夹,这里我们创建的工程目录如下。

demo                # 工程目录文件夹
  |_ conf           # 配置目录
    |_ nginx.conf   # Nginx配置文件
  |_ logs           # Nginx日志目录

nginx.conf

worker_processes 1;
error_log logs/error.log;

events {
    worker_connections 1024;
}

http {
    server {
        listen 8000;
        location / {
            default_type text/html;

            content_by_lua_block {
                ngx.print("Hello, world!")
            }
        }
    }
}

代码中我们让Nginx监听8000端口,收到请求时,我们使用Lua向HTTP客户端返回Hello, world!字符串。注意这里为了简单起见,我们的Lua脚本内联写到了nginx.conf里,实际开发中不推荐这么做。

编写好代码后,我们执行以下命令启动OpenResty的Nginx。

/opt/openresty/nginx/sbin/nginx -p demo -g "daemon off;"
  • -p:指定Nginx的工作目录
  • -g "daemon off;":以非守护进程方式在Shell前台启动Nginx,这在开发阶段比较常用

前面我们说过,openresty命令其实就是nginx的软链接,因此Nginx启停、检查配置等命令行选项都是通用的,这部分具体可以参考Nginx相关的笔记章节。

Nginx启动后便可以使用浏览器或HTTP客户端进行测试了,我们这里使用curl命令访问。

curl localhost:8000 -v

如果一切正常,我们可以看到HTTP请求成功,并返回了Hello, world!信息。

关闭Lua代码缓存(开发环境)

开发过程中我们可以关闭Lua代码缓存,这样Nginx每次处理请求时都会重新读取Lua脚本,不必每次nginx -s reload了。

lua_code_cache off;

注意该配置仅限于开发环境,生产环境不要这么做!此外它对直接写在配置文件中的Lua代码或init_by_lua_fileinit_worker_by_lua_file无效,这种情况仍然需要使用Nginx的-s reload命令重新加载配置。

将Nginx配置文件和Lua代码分离

前面的例子中,我们的Lua代码是通过content_by_lua_block嵌入Nginx配置文件中的,这种方式虽然并不是不可以,但它耦合了两种不同类型的代码,不太符合软件工程的规范要求。实际开发中,我们建议将Nginx配置文件和Lua代码分离到不同的文件夹,基于之前的例子,我们将工程目录结构调整为以下方式。

demo                # 工程目录文件夹
  |_ conf           # 配置目录
    |_ nginx.conf   # Nginx配置文件
  |_ service        # Lua源代码目录
    |_ hello.lua    # Lua源代码文件
  |_ logs           # Nginx日志目录

nginx.conf

worker_processes 1;
error_log logs/error.log;

events {
    worker_connections 1024;
}

http {
    server {
        listen 8000;
        location / {
            default_type text/html;

            content_by_lua_file 'service/hello.lua';
        }
    }
}

hello.lua

ngx.print('Hello, world!')

我们使用Lua脚本编写的逻辑被抽离到了hello.lua中,Nginx配置和之前稍有不同,我们使用了content_by_lua_file指定了Lua的源码文件。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。