Web开发平台OpenResty(一):学习资料、基本组成与使用方法

作者: 李佶澳   转载请保留:原文地址   发布时间:2018-10-25 10:12:32 +0800

说明

OpenResty是什么?被扩展的Nginx,扩展到可以直接执行Lua代码,处理业务逻辑,访问缓存和数据库等。

可以先看一下Nginx、OpenResty和Kong的基本概念与使用方法,对OpenResty有一个整体感知。

学习资料

使用OpenResty,需要对Nginx和Lua比较熟悉。

Nginx是OpenResty的执行引擎,Lua是OpenResty平台上使用的开发语言。

OpenResty的网站给出了几本关于Lua、Nginx、OpenResty的电子书

1 OpenResty的主要作者章宜春写的Programming OpenResty,好像是刚开始写…

2 章宜春写的Nginx Tutorials (version 2016.07.21),这本书有中文版

3 360公司的moonbingbing(真名不知道)组织编写的OpenResty 最佳实践,其中对Lua和Nginx也做了不错的介绍。

编程语言Lua(一):入门学习资料、基本语法与项目管理工具中收集了更多关于Lua的内容。

开发环境搭建

在mac上可以直接安装:

brew untap homebrew/nginx
brew install openresty/brew/openresty

在CentOS上的安装以及源代码编译安装,参考OpenResty编译安装

需要安装lua5.1:

brew install lua@5.1

需要安装luarocks,这里不使用brew安装luarocks,直接下载源代码安装:

brew中的luarocks使用的是lua5.3,openresty使用的是lua5.1,系统上同时存在lua5.3和lua5.1,后续用luarocks管理依赖的package、运行openresty应用时可能会遇到麻烦。

wget https://luarocks.org/releases/luarocks-3.0.3.tar.gz
tar zxpf luarocks-3.0.3.tar.gz
cd luarocks-3.0.3
$ ./configure
$ sudo make bootstrap

第一个OpenResty项目

OpenResty应用可以用openresty定制的nginx(命令openresty)运行,也可以用resty命令运行(本质上是一样的,resty是一个perl脚本,最终使用的还是openresty定制的nginx)。

用resty命令运行

用resty命令直接执行Lua代码

例如在直接写一个Lua文件

$cat hello.lua
ngx.say("hello world")

然后用OpenResty的Resty命令执行:

$ resty hello.lua
hello world

用openresty运行

可以写一个包含lua代码的nginx.conf,用openresty命令或者openresty带的nginx启动

mkdir -p  hello-world/logs
cd hello-world

创建hello-world/nginx.conf

worker_processes  1;        #nginx worker 数量
error_log logs/error.log;   #指定错误日志文件路径
events {
    worker_connections 1024;
}

http {
    server {
        #监听端口,若你的6699端口已经被占用,则需要修改
        listen 6699;
        location / {
            default_type text/html;

            content_by_lua_block {
                ngx.say("HelloWorld")
            }
        }
    }
}

在hello-world目录中启动:

openresty -p `pwd` -c nginx.conf

这时候用ps命令可以看到nginx进程(openresty命令是连接到nginx命令的符号连接):

$ ps aux|grep nginx
nginx: worker process
nginx: master process openresty -p /Users/lijiao/study-OpenResty/example/01-hello-world -c nginx.conf

访问应用:

$ curl 127.0.0.1:6699
HelloWorld

OpenResty的退出、重启、重新加载等操作,用-s指定对应的信号:

-s signal : send signal to a master process: stop, quit, reopen, reload

例如重新加载:

openresty -s reload

OpenResty与Lua的关系

OpenResty和Lua不是一回事。

Lua是一个小巧精炼编程语言,Lua的解释器有很多种,可以到编程语言Lua(一):介绍、入门学习资料、基本语法与项目管理中了解。

OpenResty是一个高度定制的Nginx,集成了NginxLua模块,支持Lua语言。

同样一段Lua代码,用OpenResty可以执行,直接用Lua命令可能不能执行:

例如下面的代码:

$ cat hello.lua
#! /usr/bin/env lua
--
-- hello.lua
-- Copyright (C) 2018 lijiaocn <lijiaocn@foxmail.com>
--
-- Distributed under terms of the GPL license.
--

ngx.say("hello world")

用OpenResty可以执行:

$ resty hello.lua
hello world

用Lua不可以:

$ lua-5.1 ./hello.lua
lua-5.1: ./hello.lua:9: attempt to index global 'ngx' (a nil value)
stack traceback:
	./hello.lua:9: in main chunk
	[C]: ?

用Lua命令执行的时候,提示找不到ngx。

这是因为OpenResty包含的一些Lua Package不在Lua的安装目录中,而是在OpenResty自己的安装目录中。

以Mac为例,用brew install openresty/brew/openresty安装的openresty,它的Package目录是:

$ ls /usr/local/Cellar/openresty/1.13.6.2/
COPYRIGHT                     homebrew.mxcl.openresty.plist pod
INSTALL_RECEIPT.json          luajit                        resty.index
README.markdown               lualib                        site
bin                           nginx
$ ls /usr/local/Cellar/openresty/1.13.6.2/lualib
cjson.so ngx      redis    resty

因此你会发现,使用openresty的项目代码中引用require "resty.core",在lua的package目录中却怎么也找不到。

因为它是openresty中的模块,位于openresty的安装目录中:

$ ls /usr/local/Cellar/openresty/1.13.6.2/lualib/resty/core
base.lua     base64.lua   ctx.lua      exit.lua  ....

在使用IDE开发代码时,为了能够跳转到OpenResty的模块中,需要将OpenResty的模块目录加入到SDK的ClassPath/SourcePath中。

OpenResty项目示例:Kong

Kong是一个在OpenResty上实现的API网关应用,这里通过kong来了解OpenResty应用的源码的组织方式。

下载Kong的代码:

git clone https://github.com/Kong/kong
cd kong

kong使用luarocks管理依赖,依赖的package记录在kong-0.14.1-0.rockspec文件中:

$ cat kong-0.14.1-0.rockspec
...
dependencies = {
  "inspect == 3.1.1",
  "luasec == 0.6",
  "luasocket == 3.0-rc1",
  "penlight == 1.5.4",
  "lua-resty-http == 0.12",
  "lua-resty-jit-uuid == 0.0.7",
  "multipart == 0.5.5",
...

kong项目的发布方式也记录在kong-0.14.1-0.rockspec文件中,记录了模块与代码文件的对应关系:

kong-0.14.1-0.rockspec

build = {
  type = "builtin",
  modules = {
    ["kong"] = "kong/init.lua",
    ["kong.meta"] = "kong/meta.lua",
    ["kong.cache"] = "kong/cache.lua",
    ["kong.global"] = "kong/global.lua",
    ["kong.router"] = "kong/router.lua",
    ...

make的时候,是直接用luarocks命令将kong安装到系统中:

install:
   @luarocks make OPENSSL_DIR=$(OPENSSL_DIR) CRYPTO_DIR=$(OPENSSL_DIR)

安装之后,在通过OpenResty执行的lua脚本中就可以引用kong了,例如文件bin/kong中引用kong的模块kong.cmd.init

$ cat bin/kong
#!/usr/bin/env resty

require "luarocks.loader"

package.path = "./?.lua;./?/init.lua;" .. package.path

require("kong.cmd.init")(arg)

OpenResty项目IDE设置

使用OpenResty的项目可以使用Lua的IDE,OpenResty虽然和Lua不是一回事,但它可以复用Lua的项目工具,使用的时候别忘了将OpenResty的模块导入到SDK中。

在IntelliJ Idea中的设置方法参考:Lua的项目管理工具-IntelliJ Idea

OpenResty对Nginx的扩展

在前面的例子中,nginx.conf中有一段配置是这样的:

            content_by_lua_block {
                ngx.say("HelloWorld")
            }

这里的content_by_lua_block指令不是原生的nginx指令,是OpenResty为Nginx增加的指令。

Nginx使用模块化设计,支持接入第三方的模块,第三方模块可以为nginx添加新的配置指令。

OpenResty为标准的Nginx添加了很多模块,大大增强了Nginx的能力。

OpenResty收录的Nginx模块

OpenResty的应用开发过程,主要就是与OpenResty添加的Nginx模块,以及各种Lua的Package打交道的过程。

熟悉OpenResty为Nginx添加的每个模块的用途是必须的,下面是OpenResty的网站上列出的Nginx模块:

array-var-nginx-module,为nginx.conf增加数组类型的变量

ngx_http_auth_request_module,为nginx.conf增加了授权指令

ngx_coolkit,收集了一些比较小巧有用的插件

drizzle-nginx-module,增加了访问mysql的功能

echo-nginx-module,增加了echo系列响应指令

encrypted-session-nginx-module,增加了加解密功能

form-input-nginx-module,读取解析POST和PUT请求的body

headers-more-nginx-module,修改响应头

iconv-nginx-module,编码转换

memc-nginx-module,对接memcache

lua-nginx-module,使nginx能够识别执行lua代码

lua-upstream-nginx-module,将lua-nginx-module模块中的lua api导入到upstreams配置中。

ngx_postgres,增加了访问postgre数据库的功能

rds-csv-nginx-module,将RDS格式数据转换成CSV格式

rds-json-nginx-module,将RDS格式数据转换成JSON格式

HttpRedisModule,增加了访问redis的功能

redis2-nginx-module,支持redis 2.0协议

set-misc-nginx-module,为ngxin的rewrite模块增加的set_XX指令

srcache-nginx-module,增加了缓存功能

ngx_stream_lua_module,为Nginx的stream/tcp增加lua支持

xss-nginx-module,添加跨站支持

模块示例:LuaNginxModule

每个模块都定义了自己的指令,可以到它们各自的项目中查看,OpenResty Componentes

LuaNginxModule为例,增加了下面的Nginx指令(directives)

lua_capture_error_log
lua_use_default_type
lua_malloc_trim
lua_code_cache
lua_regex_cache_max_entries
lua_regex_match_limit
...
content_by_lua
content_by_lua_block
content_by_lua_file
rewrite_by_lua
rewrite_by_lua_block
rewrite_by_lua_file
...

其中content_by_lua_block等指令,支持lua代码:

content_by_lua_block {
     ngx.say("I need no extra escaping here, for example: \r\nblah")
 }

LuaNginxModule还实现了Nginx的lua接口,可以在**_lua_block样式的指令中直接调用,例如上面的ngx.say

Nginx的lua接口比较多,下面只列出了一部分,可以到链接中查看全部: … ngx.ctx ngx.location.capture ngx.location.capture_multi ngx.status ngx.header.HEADER ngx.resp.get_headers ngx.req.is_internal …

OpenResty收录的Lua Package

除了Nginx模块,OpenResty还收录了一些Lua Package,这些Lua Package有一些是用C语言开发的,可以用Lua调用,但在IDE中无法跳转到它们的实现。

OpenResty收录的这些Lua Package,被安装到了OpenResty的安装目录中:

$ ls /usr/local/Cellar/openresty/1.13.6.2/lualib/resty/
aes.lua       core.lua      limit         lrucache      md5.lua       mysql.lua
...

下面是OpenResty网站列出的收录的Package,有的项目中有多个Lua模块,导入一栏中只列出了其中一个,可以它们的源码中查看:

语言    导入 源码
C require “cjson” LuaCjsonLibrary
C require “rds.parser” LuaRdsParserLibrary
C require “redis.parser” LuaRedisParserLibrary
Lua require “resty.core” LuaRestyCoreLibrary
Lua require “resty.dns.resolver” LuaRestyDNSLibrary
Lua require “resty.lock” LuaRestyLockLibrary
Lua require “resty.lrucache” LuaRestyLrucacheLibrary
Lua require “resty.memcached” LuaRestyMemcachedLibrary
Lua require “resty.mysql” LuaRestyMySQLLibrary
Lua require “resty.redis” LuaRestyRedisLibrary
Lua require “resty.sha1” LuaRestyStringLibrary
Lua require “resty.upload” LuaRestyUploadLibrary
Lua require “resty.upstream.healthcheck”   LuaRestyUpstreamHealthcheckLibrary
Lua require “resty.websocket.server” LuaRestyWebSocketLibrary
Lua require “resty.limit.conn” LuaRestyLimitTrafficLibrary

还有处于试验状态的opm命令,用来管理在OpenResty中使用的Lua Package。

OpenResty的接口调用

OpenResty自身的接口有两部分,一部分是集成的Nginx模块实现的Lua接口,另一部分是收录的Lua Package,它们都位于lualib目录中:

$ ls -F  /usr/local/Cellar/openresty/1.13.6.2/lualib
cjson.so* ngx/      redis/    resty/

如果集成的Nginx的模块实现的Lua接口,可以直接在Lua代码中调用。(不是十分确定,下文的ngx.say()是不需要明确引入package就可以执行的 2018-10-27 14:40:34)

例如“第一个OpenResty项目”的例子中,直接调用LuaNginxModule实现的Nginx的Lua接口ngx.say,不需要引入lua的package。

$ cat hello.lua
ngx.say("hello world")

Lua Package用require引用,例如:

require "resty.core"

需要注意的是lua-nginx-module的部分接口不在lua代码中,见nginx api for lua

ngx.arg
ngx.var.VARIABLE
Core constants
HTTP method constants
HTTP status constants
Nginx log level constants
print
ngx.ctx
ngx.location.capture
ngx.location.capture_multi
ngx.status
ngx.header.HEADER
ngx.resp.get_headers
ngx.req.is_internal
...

参考

  1. Nginx、OpenResty和Kong的基本概念与使用方法
  2. OpenResty Website
  3. 编程语言(一):Lua介绍、入门学习资料、基本语法与项目管理工具
  4. OpenResty 最佳实践
  5. OpenResty编译安装
  6. OpenResty Reference
  7. Project:lua-nginx-module
  8. lua-nginx-module directives
  9. lua-nginx-module: nginx lua api
  10. Lua的项目管理工具
  11. OpenResty Components

限时活动,每邀请一人即返回25元!

Copyright @2011-2018 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: lijiaocn@foxmail.com,备注网站合作 友情链接: lijiaocn github.com