Web開發平臺OpenResty(一):學習資料、基本組成與使用方法
說明
ofollow,noindex" target="_blank">OpenResty 是什麼?被擴充套件的Nginx,擴充套件到可以直接執行Lua程式碼,處理業務邏輯,訪問快取和資料庫等。
可以先看一下Nginx、OpenResty和Kong的基本概念與使用方法 ,對OpenResty有一個整體感知。
OpenResty學習資料
使用OpenResty,需要對Nginx和Lua比較熟悉。
Nginx是OpenResty的執行引擎,Lua是OpenResty平臺上使用的開發語言。
OpenResty的網站 給出了幾本關於Lua、Nginx、OpenResty的電子書 :
1OpenResty的主要作者章宜春寫的Programming OpenResty ,好像是剛開始寫…
2章宜春寫的Nginx Tutorials (version 2016.07.21) ,這本書有中文版
3360公司的moonbingbing (真名不知道)組織編寫的OpenResty 最佳實踐 ,其中對Lua和Nginx也做了不錯的介紹。
程式語言Lua(一):入門學習資料、基本語法與專案管理工具 中收集了更多關於Lua的內容。
OpenResty開發環境搭建
在mac上可以直接安裝:
brew untap homebrew/nginx brew install openresty/brew/openresty
在CentOS上的安裝以及原始碼編譯安裝,參考OpenResty編譯安裝。
需要安裝lua5.1:
brew install [email protected]
需要安裝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命令執行
例如在直接寫一個Lua檔案
$cat hello.lua ngx.say("hello world")
然後用OpenResty的Resty命令執行:
$ resty hello.lua hello world
用openresty執行
可以寫一個包含lua程式碼的nginx.conf,用openresty命令或者openresty帶的nginx啟動
mkdir -phello-world/logs cd hello-world
建立hello-world/nginx.conf
:
worker_processes1;#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與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 <[email protected]> -- -- 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/ COPYRIGHThomebrew.mxcl.openresty.plist pod INSTALL_RECEIPT.jsonluajitresty.index README.markdownlualibsite binnginx $ ls /usr/local/Cellar/openresty/1.13.6.2/lualib cjson.so ngxredisresty
因此你會發現,使用openresty的專案程式碼中引用require "resty.core"
,在lua的package目錄中卻怎麼也找不到。
因為它是openresty中的模組,位於openresty的安裝目錄中:
$ ls /usr/local/Cellar/openresty/1.13.6.2/lualib/resty/core base.luabase64.luactx.luaexit.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.luacore.lualimitlrucachemd5.luamysql.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” | LuaRestySQL/">MySQLLibrary |
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” | LuaRestySocket/">WebSocketLibrary |
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"