http://www.ttlsa.com/nginx/nginx-lua/php
1.1. 介紹
ngx_lua – 把lua語言嵌入nginx中,使其支持lua來快速開發基於nginx下的業務邏輯
該模塊不在nginx源碼包中,需自行下載編譯安裝。使用lua 5.1(目前不支持lua 5.2) 或 luajit 2.0 。
添加lua支持後,開發複雜的模塊,週期快,依然是100%異步非阻塞。mysql
ngx_lua 哪些人在用:
淘寶、騰訊財經、網易財經、360、去哪兒網等
CloudFlare, CNN, Wingify, Reblaze, Turner, Broadcasting Systemnginx
該項目主要開發者:
chaoslawful Taobao, Alibaba Grp.
agentzh CloudFlare
https://github.com/chaoslawful/lua-nginx-modulegit
1.2. 安裝
1.2.1. 安裝JIT平臺
JIT
一般,程序有兩種運行方式:靜態編譯與動態直譯。
靜態編譯的程序在執行前所有被翻譯爲機器碼,而動態直譯執行的則是一句一句邊運行邊翻譯。
即時編譯(Just-In-Time Compiler)則混合了這兩者,一句一句編譯源代碼,可是會將翻譯過的代碼緩存起來以下降性能損耗。
JAVA、.NET 實現都使用即時編譯以提供高速的代碼執行。github
注意:
在nginx.conf中添加」lua_code_cache on/off」,來開啓是否將代碼緩存,因此每次變動」*.lua」文件時,必須reload nginx纔可生效。僅針對」set_by_lua_file, content_by_lua_file, rewrite_by_lua_file, and access_by_lua_file」有效, 由於其餘爲寫在配置文件中,更改代碼也必須reload nginx。在生產環境下,不能禁用cache。同時在lua代碼中使用」dofile」 或 「loadfie」 來加載外部lua腳本將不會對它進行緩存,應該使用」require」來代替。禁用cache,當且僅當在調式代碼下。sql
LuaJIT
是一個利用JIT編譯技術把Lua腳本直接編譯成機器碼由CPU運行
版本:2.0 與 2.1
當前穩定版本爲 2.0。
2.1爲版本與ngx_lua將有較大性能提高,主要是CloudFlare公司對luajit的捐贈。
FFI庫,是LuaJIT中最重要的一個擴展庫。
1. 它容許從純Lua代碼調用外部C函數,使用C數據結構;
2. 就不用再像Lua標準math庫同樣,編寫Lua擴展庫;
3. 把開發者從開發Lua擴展C庫(語言/功能綁定庫)的繁重工做中釋放出來;api
下載編譯緩存
wget -c http://luajit.org/download/LuaJIT-2.0.2. tar .gz |
tar xzvf LuaJIT-2.0.2. tar .gz |
make install PREFIX=/usr/ local /luajit |
echo "/usr/local/luajit/lib" > /etc/ld.so.conf.d/usr_local_luajit_lib.conf |
export LUAJIT_LIB=/usr/ local /luajit/lib |
export LUAJIT_INC=/usr/ local /luajit/include/luajit-2.0 |
1.2.2. NDK與Lua_module
NDK(Nginx Development Kit)模塊是一個拓展Nginx服務器核心功能的模塊
第三方模塊開發能夠基於它來快速實現
NDK提供函數和宏處理一些基本任務,減輕第三方模塊開發的代碼量。服務器
wget -c https://github.com/simpl/ngx_devel_kit/archive/v0.2.18. tar .gz |
wget -c https://github.com/chaoslawful/lua-nginx-module/archive/v0.8.6. tar .gz |
1.2.3. 編譯安裝Nginx數據結構
wget -c http://nginx.org/download/nginx-1.4.2. tar .gz |
tar xzvf nginx-1.4.2. tar .gz |
./configure --add-module=../ngx_devel_kit-0.2.18/ --add-module=../lua-nginx-module-0.8.6/ |
1.3. 嵌入Lua後
1.3.1. 檢測版本
本身編譯官方的 nginx 源碼包,只需事前指定 LUAJIT_INC 和 LUAJIT_LIB 這兩個環境變量。
驗證你的 LuaJIT 是否生效,能夠經過下面這個接口:
location = /lua-version { |
若是使用的是標準 Lua,訪問 /lua-version 應當返回響應體 Lua 5.1
若是是 LuaJIT 則應當返回相似 LuaJIT 2.0.2 這樣的輸出。
不要使用標準lua,應當使用luajit, 後者的效率比前者高多了。
也能夠直接用 ldd 命令驗證是否鏈了 libluajit-5.1 這樣的 .so 文件,例如:
[root@limq5 sbin]# ldd nginx | grep lua
libluajit-5.1.so.2 => /usr/local/luajit/lib/libluajit-5.1.so.2 (0x00007f48e408b000)
[root@limq5 sbin]#
1.3.2. Hello,World
在nginx.conf中的service添加一個location。
ngx.log(ngx.ERR, "err err err" ) |
用戶訪問 http://localhost/test 將會打印出「Hello World」內容。
ngx.say 是 lua 顯露給模塊的接口。
相似的有 ngx.log(ngx.DEBUG, 「」),能夠在error.log輸出調試信息。
另外也能夠調用外部腳本,如同咱們寫php、jsp應用時,業務腳本單獨組織在.php或.jsp文件中同樣
content_by_lua_file conf/lua/hello.lua; |
文件hello.lua內容以下:
ngx.say(「Hello World」)
這裏的腳本能夠任意複雜,也可使用Lua 本身的庫
lua可用模塊列表:
http://luarocks.org/repositories/rocks/
安裝相似yum,它也有一個倉庫:
luarocks install luafilesystem
運行上面命令後,會編譯一個 「lfs.so」, 文件,拷貝文件到nginx定義的LUA_PATH中,而後引用該庫,就可調用其中函數。
LUA_PATH:
lua_package_path ‘/opt/17173/nginx-ds/conf/lua/?.lua;;’
lua_package_cpath ‘/opt/17173/nginx-ds/conf/lua/lib/?.so;/usr/local/lib/?.?;;’;
其中」;;」表明原先查找範圍。
1.3.3. 同步形式,異步執行
咱們假定,同時要訪問多個數據源,並且,查詢是沒有依賴關係,那咱們就能夠同時發出請求
這樣我總的延時, 是我全部請求中最慢的一個所用時間,而不是原先的全部請求用時的疊加
ngx.location.capture_multi{ |
{ "/memc" }, { "/mysql" }, { "/postgres" } |
ngx.say(res1.body, res2.body, res3.body) |
ngx.location.capture 沒法跨server進行處理, 只能在同一個server下的不一樣location。
1.4. Nginx與Lua執行順序
1.4.1. Nginx順序
Nginx 處理每個用戶請求時,都是按照若干個不一樣階段(phase)依次處理的,而不是根據配置文件上的順序。
Nginx 處理請求的過程一共劃分爲 11 個階段,按照執行順序依次是
post-read、server-rewrite、find-config、rewrite、post-rewrite、 preaccess、access、post-access、try-files、content、log.
post-read:
讀取請求內容階段
Nginx讀取並解析完請求頭以後就當即開始運行
例如模塊 ngx_realip 就在 post-read 階段註冊了處理程序,它的功能是迫使 Nginx 認爲當前請求的來源地址是指定的某一個請求頭的值。
server-rewrite
Server請求地址重寫階段
當 ngx_rewrite 模塊的set配置指令直接書寫在 server 配置塊中時,基本上都是運行在 server-rewrite 階段
find-config
配置查找階段
這個階段並不支持 Nginx 模塊註冊處理程序,而是由 Nginx 核心來完成當前請求與 location 配置塊之間的配對工做。
rewrite
Location請求地址重寫階段
當 ngx_rewrite 模塊的指令用於 location 塊中時,即是運行在這個 rewrite 階段。
另外,ngx_set_misc(設置md五、encode_base64等) 模塊的指令,還有 ngx_lua 模塊的 set_by_lua 指令和 rewrite_by_lua 指令也在此階段。
post-rewrite
請求地址重寫提交階段
由 Nginx 核心完成 rewrite 階段所要求的「內部跳轉」操做,若是 rewrite 階段有此要求的話。
preaccess
訪問權限檢查準備階段
標準模塊 ngx_limit_req 和 ngx_limit_zone 就運行在此階段,前者能夠控制請求的訪問頻度,然後者能夠限制訪問的併發度。
access
訪問權限檢查階段
標準模塊 ngx_access、第三方模塊 ngx_auth_request 以及第三方模塊 ngx_lua 的 access_by_lua 指令就運行在這個階段。
配置指令可能是執行訪問控制性質的任務,好比檢查用戶的訪問權限,檢查用戶的來源 IP 地址是否合法
post-access
訪問權限檢查提交階段
主要用於配合 access 階段實現標準 ngx_http_core 模塊提供的配置指令 satisfy 的功能。
satisfy all(與關係)
satisfy any(或關係)
try-files
配置項try_files處理階段
專門用於實現標準配置指令 try_files 的功能
若是前 N-1 個參數所對應的文件系統對象都不存在,try-files 階段就會當即發起「內部跳轉」到最後一個參數(即第 N 個參數)所指定的 URI.
content
內容產生階段
Nginx 的 content 階段是全部請求處理階段中最爲重要的一個,由於運行在這個階段的配置指令通常都肩負着生成「內容」並輸出 HTTP 響應的使命。
log
日誌模塊處理階段
記錄日誌
淘寶有開放一個nginx開發手冊,裏面包含不少有用的資料
http://tengine.taobao.org/book/
做者的google論壇:
https://groups.google.com/forum/#!forum/openresty
1.4.2. Lua順序
Nginx下Lua處理階段與使用範圍:
set_by_lua server, server if , location, location if |
rewrite_by_lua http, server, location, location if |
access_by_lua http, server, location, location if |
content_by_lua location, location if |
header_filter_by_lua http, server, location, location if |
body_filter_by_lua http, server, location, location if |
log_by_lua http, server, location, location if |
init_by_lua:
在nginx從新加載配置文件時,運行裏面lua腳本,經常使用於全局變量的申請。
例如lua_shared_dict共享內存的申請,只有當nginx重起後,共享內存數據才清空,這經常使用於統計。
set_by_lua:
設置一個變量,經常使用與計算一個邏輯,而後返回結果
該階段不能運行Output API、Control API、Subrequest API、Cosocket API
rewrite_by_lua:
在access階段前運行,主要用於rewrite
access_by_lua:
主要用於訪問控制,能收集到大部分變量,相似status須要在log階段纔有。
這條指令運行於nginx access階段的末尾,所以老是在 allow 和 deny 這樣的指令以後運行,雖然它們同屬 access 階段。
content_by_lua:
階段是全部請求處理階段中最爲重要的一個,運行在這個階段的配置指令通常都肩負着生成內容(content)並輸出HTTP響應。
header_filter_by_lua:
通常只用於設置Cookie和Headers等
該階段不能運行Output API、Control API、Subrequest API、Cosocket API
body_filter_by_lua:
通常會在一次請求中被調用屢次, 由於這是實現基於 HTTP 1.1 chunked 編碼的所謂「流式輸出」的。
該階段不能運行Output API、Control API、Subrequest API、Cosocket API
log_by_lua:
該階段老是運行在請求結束的時候,用於請求的後續操做,如在共享內存中進行統計數據,若是要高精確的數據統計,應該使用body_filter_by_lua。
該階段不能運行Output API、Control API、Subrequest API、Cosocket API
timer:
可參考官方文檔:http://wiki.nginx.org/HttpLuaModule