您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何通過 Lua 擴(kuò)展 Nginx”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何通過 Lua 擴(kuò)展 Nginx”吧!
Nginx 模塊需要用 C 開發(fā),而且必須符合一系列復(fù)雜的規(guī)則,最重要的用 C 開發(fā)模塊必須要熟悉 Nginx 的源代碼,使得開發(fā)者對(duì)其望而生畏。
ngx_lua 模塊通過將 lua 解釋器集成進(jìn) Nginx,可以采用 lua 腳本實(shí)現(xiàn)業(yè)務(wù)邏輯。
該模塊具有以下特性:
高并發(fā)、非阻塞地處理各種請(qǐng)求。
Lua 內(nèi)建協(xié)程,這樣就可以很好地將異步回調(diào)轉(zhuǎn)換成順序調(diào)用的形式。
每個(gè)協(xié)程都有一個(gè)獨(dú)立的全局環(huán)境(變量空間),繼承于全局共享的、只讀的“comman data”。
得益于 Lua 協(xié)程的支持,ngx_lua 在處理 10000 個(gè)并發(fā)請(qǐng)求時(shí)只需要很少的內(nèi)存。根據(jù)測(cè)試,ngx_lua 處理每個(gè)請(qǐng)求只需要 2KB 的內(nèi)存,如果使用 LuaJIT 則會(huì)更少。
ngx_lua 非常適合用于實(shí)現(xiàn)可擴(kuò)展的、高并發(fā)的服務(wù)。
協(xié)程并非 os 線程,所以創(chuàng)建、切換開銷比線程相對(duì)較小。
協(xié)程與線程一樣有自己的棧、局部變量等,但是協(xié)程的棧是在用戶進(jìn)程空間模擬的,所以創(chuàng)建、開銷很小。
多線程程序是多個(gè)線程并發(fā)執(zhí)行,也就是說(shuō)在一瞬間有多個(gè)控制流在執(zhí)行。而協(xié)程強(qiáng)調(diào)的是一種多個(gè)協(xié)程間協(xié)作的關(guān)系,只有當(dāng)一個(gè)協(xié)程主動(dòng)放棄執(zhí)行權(quán),另一個(gè)協(xié)程才能取得執(zhí)行權(quán),所以在某一瞬間,多個(gè)協(xié)程間只有一個(gè)在運(yùn)行。
由于多個(gè)協(xié)程是只有一個(gè)在運(yùn)行,所以對(duì)于臨界區(qū)的訪問不需要加鎖,而多線程的情況則必須加鎖。
多線程程序由于有多個(gè)控制流,所以程序的行為不可控,而多個(gè)協(xié)程的執(zhí)行是由開發(fā)者定義的所以是可控的。
Nginx 的每個(gè) Worker 進(jìn)程都是在 epoll 或 kqueue 這樣的事件模型之上,封裝成協(xié)程,每個(gè)請(qǐng)求都有一個(gè)協(xié)程進(jìn)行處理。這正好與 Lua 內(nèi)建協(xié)程的模型是一致的,所以即使 ngx_lua 需要執(zhí)行 lua,相對(duì) C 有一定的開銷,但依然能保證高并發(fā)能力。
Nginx 采用多進(jìn)程模型,單Master-多Worker,Master 進(jìn)程主要用來(lái)管理 Worker 進(jìn)程。
Worker 進(jìn)程采用單線程、非阻塞地事件模型(Event Loop,事件循環(huán))來(lái)實(shí)現(xiàn)端口的監(jiān)聽及客戶端請(qǐng)求的處理和響應(yīng),同時(shí) Worker 還要處理來(lái)自 Master 的信號(hào)。Worker 進(jìn)程個(gè)數(shù)一般設(shè)置為機(jī)器 CPU 核數(shù)。
接受來(lái)自外界的信號(hào)。
向各 Worker 進(jìn)程發(fā)送信號(hào)。
監(jiān)控 Worker 進(jìn)程的運(yùn)行狀態(tài)。
當(dāng) Worker 進(jìn)程退出后(異常情況下),會(huì)自動(dòng)重新啟動(dòng)新的 Worker 進(jìn)程。
階段 | 說(shuō)明 |
---|---|
post-read | 讀取請(qǐng)求內(nèi)容階段,nginx 讀取并解析完請(qǐng)求頭之后就立即開始運(yùn)行 |
server-rewrite | server 請(qǐng)求地址重寫階段 |
find-config | 配置查找階段,用來(lái)完成當(dāng)前請(qǐng)求與 location 配置塊之間的配置工作 |
rewrite | location 請(qǐng)求地址重寫階段,當(dāng) ngx_rewrite 指令用于 location 中,就是在這個(gè)階段運(yùn)行的 |
post-rewrite | 請(qǐng)求地址重寫階段,當(dāng) nginx 完成 rewrite 階段所要求的內(nèi)部跳轉(zhuǎn)動(dòng)作,如果 rewrite 階段有這個(gè)要求的話 |
preaccess | 訪問權(quán)限檢查準(zhǔn)備階段,ngx_limit_req 和 ngx_limit_zone 在這個(gè)階段運(yùn)行,ngx_limit_req 可以控制請(qǐng)求的訪問頻率,ngx_limit_zone 可以控制訪問的并發(fā)度。 |
access | 權(quán)限檢查階段,ngx_access 在這個(gè)階段運(yùn)行,配置指令多是執(zhí)行訪問控制相關(guān)的任務(wù),入檢查用戶的訪問權(quán)限,檢查用戶的來(lái)源 IP 是否合法 |
post-access | 訪問權(quán)限檢查提交階段 |
try-files | 配置 try_files 處理階段 |
content | 內(nèi)容產(chǎn)生階段,是所有請(qǐng)求處理階段中最為重要的階段,因?yàn)檫@個(gè)階段的指令通常是用來(lái)生成 HTTP 響應(yīng)內(nèi)容的 |
log | 日志模塊處理階段 |
ngx_lua 屬于 nginx 的一部分,它的執(zhí)行指令都包含在 nginx 的 11 個(gè)步驟之中了,相應(yīng)的處理階段可以做插入式處理,即可插拔式架構(gòu),不過 ngx_lua 并不是所有階段都會(huì)運(yùn)行的;另外指令可以在 http、server、server if、location、location if 幾個(gè)范圍進(jìn)行配置。
指令 | 所處處理階段 | 使用范圍 | 解釋 |
---|---|---|---|
init_by_lua<br/>init_by_lua_file | loading-config | http | nginx Master 進(jìn)程加載配置時(shí)執(zhí)行;<br/>通常用于初始化全局配置/預(yù)加載 Lua 模塊 |
init_worker_by_lua<br/>init_worker_by_lua_file | starting-worker | http | 每個(gè) Nginx Worker 進(jìn)程啟動(dòng)時(shí)調(diào)用的計(jì)時(shí)器,如果 Master 進(jìn)程不允許<br/>則只會(huì)在 init_by_\lua 之后調(diào)用;通常用于定時(shí)拉取配置/數(shù)據(jù),<br/>或者后端服務(wù)的健康檢查。 |
set_by_lua<br/>set_by_lua_file | rewrite | server,server if,location,location if | 設(shè)置 nginx 變量,可以實(shí)現(xiàn)復(fù)雜的賦值邏輯;此處是阻塞的,Lua 代碼要做到非常快 |
write_by_lua<br/>rewrite_by_lua_file | rewrite tail | http,server,location,location if | rewrite 階段處理,可以實(shí)現(xiàn)復(fù)雜的轉(zhuǎn)發(fā)/重定向邏輯。 |
access_by_lua<br/>access_by_lua_file | access tail | http,server,location,location if | 請(qǐng)求訪問階段處理,用于訪問控制 |
content_by_lua<br/>content_by_lua_file | content | location,location if | 內(nèi)容處理器,接受請(qǐng)求處理并輸出響應(yīng) |
header_filter_by_lua<br/>header_filter_by_lua_file | output-header-first | http,server,location,location if | 設(shè)置 header 和 cookie |
body_filter_by_lua<br/>body_filter_by_lua_file | output-body-filter | http,server,location,location if | 對(duì)響應(yīng)數(shù)據(jù)進(jìn)行過濾,比如截?cái)唷⑻鎿Q |
log_by_lua<br/>log_by_lua_file | log | http,server,location,location if | log 階段處理,比如記錄訪問量/統(tǒng)計(jì)平均響應(yīng)時(shí)間 |
OpenResty 是一個(gè)基于 Nginx 與 Lua 的高性能 Web 平臺(tái),其內(nèi)部集成了大量精良的 Lua 庫(kù)、第三方模塊以及大多數(shù)的依賴項(xiàng)。用于方便地搭建能夠處理超高并發(fā)、擴(kuò)展性極高的動(dòng)態(tài) Web 應(yīng)用、Web 服務(wù)和動(dòng)態(tài)網(wǎng)關(guān)。
OpenResty 通過匯聚各種設(shè)計(jì)精良的 Nginx 模塊(主要由 OpenResty 團(tuán)隊(duì)自主開發(fā)),從而將 Nginx 有效地變成一個(gè)強(qiáng)大的通用 Web 應(yīng)用平臺(tái)。這樣,Web 開發(fā)人員和系統(tǒng)工程師可以使用 Lua 腳本語(yǔ)言調(diào)用 Nginx 支持的各種 C 以及 Lua 模塊,快速構(gòu)造出足以勝任 10k 乃至 1000k 以上單機(jī)并發(fā)連接的高性能 Web 應(yīng)用系統(tǒng)。
OpenResty 的目標(biāo)是讓你的 Web 服務(wù)直接跑在 Nginx 服務(wù)內(nèi)部,充分利用 Nginx 的非阻塞 I/O 模型,不僅僅對(duì) HTTP 客戶端請(qǐng)求,甚至于對(duì)遠(yuǎn)程后端諸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都進(jìn)行一致的高性能響應(yīng)。
content_by_lua
:內(nèi)容處理器,接收請(qǐng)求處理并輸出響應(yīng)。
該指令工作在 Nginx 處理流程的 content 階段,即內(nèi)容產(chǎn)生階段,是所有請(qǐng)求處理階段中最為重要的階段,因?yàn)檫@個(gè)階段的指令通常是用來(lái)生成 HTTP 響應(yīng)內(nèi)容的。
測(cè)試
輸出: $ curl http://127.0.0.1/ $ Hello,world
user www-data; worker_processes auto; pid /run/nginx.pid; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 8080; location / { default_type text/html; content_by_lua ' ngx.say("<p>Hello, world!</p>") '; } } }
user www-data; worker_processes auto; pid /run/nginx.pid; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 8080; location / { default_type text/html; content_by_lua_block { ngx.say('Hello, world!') } } } }
啟動(dòng) /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_01.conf 測(cè)試 curl -i http://127.0.0.1/
user www-data; worker_processes auto; pid /run/nginx.pid; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 8080; location /lua_1 { default_type text/html; content_by_lua_block { ngx.say('Hello, world! @ Time 1!') ngx.sleep(3) ngx.say('Hello, world! @ Time 2!') } } } }
啟動(dòng) /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_02.conf 測(cè)試 curl -i http://127.0.0.1/lua_1 curl -i http://127.0.0.1/lua_1
user www-data; worker_processes auto; pid /run/nginx.pid; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 8080; location /lua_1 { default_type text/html; content_by_lua_block { ngx.say(ngx.var.arg_a) } } } }
啟動(dòng) /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_03.conf 測(cè)試 curl -i http://127.0.0.1?a=nginx_lua
user www-data; worker_processes auto; pid /run/nginx.pid; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 8080; location ~/redis_lua/(\d+)$ { default_type text/html; charset utf-8; lua_code_cache on; content_by_lua_file '/home/zp/openresty/lua/redis.lua'; } } }
local json = require("cjson") local redis = require("resty.redis") local red = redis:new() red:set_timeout(1000) local ip = "127.0.0.1" local port = 6379 local ok, err = red:connect(ip, port) if not ok then ngx.say('connect to redis error: ', err) return ngx.exit(500) end local id = ngx.var[1] local value = "calue-"..id red:set(id, value) local resp, err = red:get(id) if not resp then ngx.say('get from redis error: ', err) return ngx.exit(500) end red:close() ngx.say(json.encode({content=resp}))
啟動(dòng) /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_04.conf 測(cè)試 curl -i http://127.0.0.1/redis_lua/1 curl -i http://127.0.0.1/redis_lua/2 curl -i http://127.0.0.1/redis_lua/3
感謝各位的閱讀,以上就是“如何通過 Lua 擴(kuò)展 Nginx”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)如何通過 Lua 擴(kuò)展 Nginx這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。