ngx_lua模塊
Nginx模塊需要用C開發,而且必須符合一系列複雜的規則,最重要的是用C開發模塊必須要熟悉Nginx源碼,使得開發者對其望而生畏。
ngx_lua模塊通過將lua解釋器集成進Nginx,可以採用lua腳本實現業務邏輯。
該模塊具備以下特性:
1 高併發、非阻塞的處理各種請求
2 Lua內建協程,這樣就可以很好的將異步回調轉換成順序調用的形式。
3 每個協程都有一個獨立的全局環境(變量空間),繼承於全局共享的、只讀的“comman data”
得益於Lua協程的支持,ngx_lua在處理1萬個併發請求時只需要很少的內存。根據測試ngx_lua處理每個請求只需要2KB的內存,如果使用LuaJIT則會更少。
ngx_lua非常適合用於實現可擴展的、高併發的服務。
協程(Coroutine)
協程類似一種多線程,與多線程的區別有:
- 協程並非os線程,所以創建、切換開銷比線程相對要小
- 協程與線程一樣有自已的棧、局部變量等,但是協程的棧是在用戶進程空間模擬的,所以創建、切換開銷很小。
- 多線程程序是多個線程併發執行,也就是說在一瞬間有多個控制流在執行。而協程強調的是一種多個協程間協作的關係,只有當一個協程主動放棄執行權,另一個協程才能獲得執行權,所以在某一瞬間,多個協程間只有一個在運行。
- 由於多個協程時只有一個在運行,所以對於臨界區的訪問不需要加鎖,而多線程的情況則必須加鎖。
- 多線程程序由於有多個控制流,所以程序的行爲不可控,而多個協程的執行是由開發者定義的,可控的。
Nginx的每個Worker進程都是在epoll或kqueue這樣的事件模型之上,封裝成協程,每個請求都有一個協程進行處理。這正好與Lua內建協程的模型是一致的,所以即使ngx_lua需要執行Lua,相對C有一定的開銷,但依然能保證高併發能力。
Nginx進程模型
Nginx採用多進程模型,單Master - 多Worker,Master進程主要用來管理Worker進程。
Worker進程採用單線程、非阻塞的事件模型(Event Loop,事件循環)來實現端口的監聽及客戶端請求的處理和響應,同時Worker還要處理來自Master的信號。Worker進程個數一般設置爲機器CPU核數。
Master進程具體包括如下4個主要功能:
- 接收來自外界的信號
- 向各Worker進程發送信號
- 監控Worker進程的運行狀態
- 當Worker進程退出後(異常情況下),會自動重新啓動新的Worker進程。
HTTP請求處理
階段 | 說明 |
---|---|
post-read | 讀取請求內容階段,nginx讀取並解析完請求頭之後就立即開始運行 |
server-rewrite | server請求地址重寫階段 |
find-config | 配置查找階段,用來完成當前請求與location配置塊之間的配對工作 |
rewrite | location請求地址重寫階段,當ngx_rewrite指令用於location中,就是在這個階段運行的 |
post-rewrite | 請求地址重寫提交階段,當nginx完成rewrite階段所要求的內部跳轉動作,如果rewrite階段有這個要求的話 |
preacess | 訪問權限檢查準備階段,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指令
ngx_lua屬於nginx的一部分,它的執行指令都包含在nginx的11個步驟中了,相應的處理階段可以做插入式處理,即可插拔式架構,不過ngx_lua並不是所有階段都會運行的;另外指令可以在http、server、server if、location、location if幾個範圍進行配置:
指令 | 所處處理階段 | 使用範圍 | 觸角 |
---|---|---|---|
init_by_lua init_by_lua_file | loading-config | http | nginx Master進程加載配置時執行,通常用於初始化全局配置、預加載lua模塊 |
init_worker_by_lua init_worker_by_lua_file | starting-worker | http | 每個Nginx Worker進程啓動時調用的計時器,如果Master進程不允許則只會在init_by_lua之後調用;通常用於定時拉取配置、數據、或者後端服務的健康檢查 |
set_by_lua set_by_lua_file | rewrite | server,server if,location,location if | 設置nginx變量,可以實現複雜的賦值邏輯;此處是阻塞的,Lua代碼要做到非常快; |
rewrite_by_lua rewrite_by_lua_file | rewrite tail | http,server,location,location if | rewrite階段處理,可以實現複雜的轉發、重定向邏輯 |
OpenResty
概念: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等都進行一致的高性能響應。
ngx_lua實例
content_by_lua:內容處理器,接收請求處理並輸出響應。
該指令工作在Nginx處理流程的content階段,即內容產生階段,是所有請求處理階段中最爲重要的階段,因爲這個階段的指令通常是用來生成HTTP響應內容的;
示例