您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何通過 Lua 擴展 Nginx”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何通過 Lua 擴展 Nginx”吧!
Nginx 模塊需要用 C 開發,而且必須符合一系列復雜的規則,最重要的用 C 開發模塊必須要熟悉 Nginx 的源代碼,使得開發者對其望而生畏。
ngx_lua 模塊通過將 lua 解釋器集成進 Nginx,可以采用 lua 腳本實現業務邏輯。
該模塊具有以下特性:
高并發、非阻塞地處理各種請求。
Lua 內建協程,這樣就可以很好地將異步回調轉換成順序調用的形式。
每個協程都有一個獨立的全局環境(變量空間),繼承于全局共享的、只讀的“comman data”。
得益于 Lua 協程的支持,ngx_lua 在處理 10000 個并發請求時只需要很少的內存。根據測試,ngx_lua 處理每個請求只需要 2KB 的內存,如果使用 LuaJIT 則會更少。
ngx_lua 非常適合用于實現可擴展的、高并發的服務。
協程并非 os 線程,所以創建、切換開銷比線程相對較小。
協程與線程一樣有自己的棧、局部變量等,但是協程的棧是在用戶進程空間模擬的,所以創建、開銷很小。
多線程程序是多個線程并發執行,也就是說在一瞬間有多個控制流在執行。而協程強調的是一種多個協程間協作的關系,只有當一個協程主動放棄執行權,另一個協程才能取得執行權,所以在某一瞬間,多個協程間只有一個在運行。
由于多個協程是只有一個在運行,所以對于臨界區的訪問不需要加鎖,而多線程的情況則必須加鎖。
多線程程序由于有多個控制流,所以程序的行為不可控,而多個協程的執行是由開發者定義的所以是可控的。
Nginx 的每個 Worker 進程都是在 epoll 或 kqueue 這樣的事件模型之上,封裝成協程,每個請求都有一個協程進行處理。這正好與 Lua 內建協程的模型是一致的,所以即使 ngx_lua 需要執行 lua,相對 C 有一定的開銷,但依然能保證高并發能力。
Nginx 采用多進程模型,單Master-多Worker,Master 進程主要用來管理 Worker 進程。
Worker 進程采用單線程、非阻塞地事件模型(Event Loop,事件循環)來實現端口的監聽及客戶端請求的處理和響應,同時 Worker 還要處理來自 Master 的信號。Worker 進程個數一般設置為機器 CPU 核數。
接受來自外界的信號。
向各 Worker 進程發送信號。
監控 Worker 進程的運行狀態。
當 Worker 進程退出后(異常情況下),會自動重新啟動新的 Worker 進程。
階段 | 說明 |
---|---|
post-read | 讀取請求內容階段,nginx 讀取并解析完請求頭之后就立即開始運行 |
server-rewrite | server 請求地址重寫階段 |
find-config | 配置查找階段,用來完成當前請求與 location 配置塊之間的配置工作 |
rewrite | location 請求地址重寫階段,當 ngx_rewrite 指令用于 location 中,就是在這個階段運行的 |
post-rewrite | 請求地址重寫階段,當 nginx 完成 rewrite 階段所要求的內部跳轉動作,如果 rewrite 階段有這個要求的話 |
preaccess | 訪問權限檢查準備階段,ngx_limit_req 和 ngx_limit_zone 在這個階段運行,ngx_limit_req 可以控制請求的訪問頻率,ngx_limit_zone 可以控制訪問的并發度。 |
access | 權限檢查階段,ngx_access 在這個階段運行,配置指令多是執行訪問控制相關的任務,入檢查用戶的訪問權限,檢查用戶的來源 IP 是否合法 |
post-access | 訪問權限檢查提交階段 |
try-files | 配置 try_files 處理階段 |
content | 內容產生階段,是所有請求處理階段中最為重要的階段,因為這個階段的指令通常是用來生成 HTTP 響應內容的 |
log | 日志模塊處理階段 |
ngx_lua 屬于 nginx 的一部分,它的執行指令都包含在 nginx 的 11 個步驟之中了,相應的處理階段可以做插入式處理,即可插拔式架構,不過 ngx_lua 并不是所有階段都會運行的;另外指令可以在 http、server、server if、location、location if 幾個范圍進行配置。
指令 | 所處處理階段 | 使用范圍 | 解釋 |
---|---|---|---|
init_by_lua<br/>init_by_lua_file | loading-config | http | nginx Master 進程加載配置時執行;<br/>通常用于初始化全局配置/預加載 Lua 模塊 |
init_worker_by_lua<br/>init_worker_by_lua_file | starting-worker | http | 每個 Nginx Worker 進程啟動時調用的計時器,如果 Master 進程不允許<br/>則只會在 init_by_\lua 之后調用;通常用于定時拉取配置/數據,<br/>或者后端服務的健康檢查。 |
set_by_lua<br/>set_by_lua_file | rewrite | server,server if,location,location if | 設置 nginx 變量,可以實現復雜的賦值邏輯;此處是阻塞的,Lua 代碼要做到非常快 |
write_by_lua<br/>rewrite_by_lua_file | rewrite tail | http,server,location,location if | rewrite 階段處理,可以實現復雜的轉發/重定向邏輯。 |
access_by_lua<br/>access_by_lua_file | access tail | http,server,location,location if | 請求訪問階段處理,用于訪問控制 |
content_by_lua<br/>content_by_lua_file | content | location,location if | 內容處理器,接受請求處理并輸出響應 |
header_filter_by_lua<br/>header_filter_by_lua_file | output-header-first | http,server,location,location if | 設置 header 和 cookie |
body_filter_by_lua<br/>body_filter_by_lua_file | output-body-filter | http,server,location,location if | 對響應數據進行過濾,比如截斷、替換 |
log_by_lua<br/>log_by_lua_file | log | http,server,location,location if | log 階段處理,比如記錄訪問量/統計平均響應時間 |
OpenResty 是一個基于 Nginx 與 Lua 的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用于方便地搭建能夠處理超高并發、擴展性極高的動態 Web 應用、Web 服務和動態網關。
OpenResty 通過匯聚各種設計精良的 Nginx 模塊(主要由 OpenResty 團隊自主開發),從而將 Nginx 有效地變成一個強大的通用 Web 應用平臺。這樣,Web 開發人員和系統工程師可以使用 Lua 腳本語言調用 Nginx 支持的各種 C 以及 Lua 模塊,快速構造出足以勝任 10k 乃至 1000k 以上單機并發連接的高性能 Web 應用系統。
OpenResty 的目標是讓你的 Web 服務直接跑在 Nginx 服務內部,充分利用 Nginx 的非阻塞 I/O 模型,不僅僅對 HTTP 客戶端請求,甚至于對遠程后端諸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都進行一致的高性能響應。
content_by_lua
:內容處理器,接收請求處理并輸出響應。
該指令工作在 Nginx 處理流程的 content 階段,即內容產生階段,是所有請求處理階段中最為重要的階段,因為這個階段的指令通常是用來生成 HTTP 響應內容的。
測試
輸出: $ 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!') } } } }
啟動 /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_01.conf 測試 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!') } } } }
啟動 /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_02.conf 測試 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) } } } }
啟動 /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_03.conf 測試 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}))
啟動 /usr/local/openresty/nginx/sbin/nginx -p `pwd` -c conf/nginx_openresty_04.conf 測試 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 擴展 Nginx”的內容了,經過本文的學習后,相信大家對如何通過 Lua 擴展 Nginx這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。