做者: 李佶澳 轉載請保留:原文地址 發佈時間:2018-10-25 10:12:32 +0800html
OpenResty是什麼?被擴展的Nginx,擴展到能夠直接執行Lua代碼,處理業務邏輯,訪問緩存和數據庫等。mysql
能夠先看一下Nginx、OpenResty和Kong的基本概念與使用方法,對OpenResty有一個總體感知。nginx
使用OpenResty,須要對Nginx和Lua比較熟悉。git
Nginx是OpenResty的執行引擎,Lua是OpenResty平臺上使用的開發語言。github
OpenResty的網站給出了幾本關於Lua、Nginx、OpenResty的電子書:web
1 OpenResty的主要做者章宜春寫的Programming OpenResty,好像是剛開始寫…redis
2 章宜春寫的Nginx Tutorials (version 2016.07.21),這本書有中文版sql
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定製的nginx(命令openresty)運行,也能夠用resty命令運行(本質上是同樣的,resty是一個perl腳本,最終使用的仍是openresty定製的nginx)。
例如在直接寫一個Lua文件
$cat hello.lua
ngx.say("hello world")
而後用OpenResty的Resty命令執行:
$ resty hello.lua
hello world
能夠寫一個包含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不是一回事。
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中。
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的項目可使用Lua的IDE,OpenResty雖然和Lua不是一回事,但它能夠複用Lua的項目工具,使用的時候別忘了將OpenResty的模塊導入到SDK中。
在IntelliJ Idea中的設置方法參考:Lua的項目管理工具-IntelliJ Idea
在前面的例子中,nginx.conf中有一段配置是這樣的:
content_by_lua_block {
ngx.say("HelloWorld")
}
這裏的content_by_lua_block
指令不是原生的nginx指令,是OpenResty爲Nginx增長的指令。
Nginx使用模塊化設計,支持接入第三方的模塊,第三方模塊能夠爲nginx添加新的配置指令。
OpenResty爲標準的Nginx添加了不少模塊,大大加強了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,添加跨站支持
每一個模塊都定義了本身的指令,能夠到它們各自的項目中查看,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 …
除了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自身的接口有兩部分,一部分是集成的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
...