通過Lua拓展Nginx

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)

協程類似一種多線程,與多線程的區別有:

  1. 協程並非os線程,所以創建、切換開銷比線程相對要小
  2. 協程與線程一樣有自已的棧、局部變量等,但是協程的棧是在用戶進程空間模擬的,所以創建、切換開銷很小。
  3. 多線程程序是多個線程併發執行,也就是說在一瞬間有多個控制流在執行。而協程強調的是一種多個協程間協作的關係,只有當一個協程主動放棄執行權,另一個協程才能獲得執行權,所以在某一瞬間,多個協程間只有一個在運行。
  4. 由於多個協程時只有一個在運行,所以對於臨界區的訪問不需要加鎖,而多線程的情況則必須加鎖。
  5. 多線程程序由於有多個控制流,所以程序的行爲不可控,而多個協程的執行是由開發者定義的,可控的。

Nginx的每個Worker進程都是在epoll或kqueue這樣的事件模型之上,封裝成協程,每個請求都有一個協程進行處理。這正好與Lua內建協程的模型是一致的,所以即使ngx_lua需要執行Lua,相對C有一定的開銷,但依然能保證高併發能力。

Nginx進程模型

Nginx採用多進程模型,單Master - 多Worker,Master進程主要用來管理Worker進程。
Worker進程採用單線程、非阻塞的事件模型(Event Loop,事件循環)來實現端口的監聽及客戶端請求的處理和響應,同時Worker還要處理來自Master的信號。Worker進程個數一般設置爲機器CPU核數。

Master進程具體包括如下4個主要功能:

  1. 接收來自外界的信號
  2. 向各Worker進程發送信號
  3. 監控Worker進程的運行狀態
  4. 當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響應內容的;
示例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章