用Nginx+Lua(OpenResty)開發高性能Web應用

在互聯網公司,Nginx能夠說是標配組件,可是主要場景仍是負載均衡、反向代理、代理緩存、限流等場景;而把Nginx做爲一個Web容器使用的還不是那麼普遍。Nginx的高性能是你們公認的,而Nginx開發主要是以C/C++模塊的形式進行,總體學習和開發成本偏高;若是有一種簡單的語言來實現Web應用的開發,那麼Nginx絕對是把好的瑞士軍刀;目前Nginx團隊也開始意識到這個問題,開發了nginxScript:能夠在Nginx中使用JavaScript進行動態配置一些變量和動態腳本執行;而目前市面上用的很是成熟的擴展是由章亦春將Lua和Nginx粘合的ngx_lua模塊,而且將Nginx核心、LuaJIT、ngx_lua模塊、許多有用的Lua庫和經常使用的第三方Nginx模塊組合在一塊兒成爲OpenResty,這樣開發人員就能夠安裝OpenResty,使用Lua編寫腳本,而後部署到Nginx Web容器中運行。從而很是輕鬆就能開發出高性能的Web服務。css

 

接下來咱們就認識下Nginx、Lua、ngx_lua模塊和ngx_lua到底能開發哪些類型的web應用。html

 

1、ngx_lua簡介

1、Nginx優勢java

Nginx設計爲一個主進程多個工做進程的工做模式,每一個進程是單線程來處理多個鏈接,並且每一個工做進程採用了非阻塞I/O來處理多個鏈接,從而減小了線程上下文切換,從而實現了公認的高性能、高併發;所以在生成環境中會經過把CPU綁定給Nginx工做進程從而提高其性能;另外由於單線程工做模式的特色,內存佔用就很是少了。mysql

Nginx更改配置重啓速度很是快,能夠毫秒級,並且支持不中止Nginx進行升級Nginx版本、動態重載Nginx配置。linux

Nginx模塊也是很是多,功能也很強勁,不只能夠做爲http負載均衡,Nginx發佈1.9.0版本還支持TCP負載均衡,還能夠很容易的實現內容緩存、web服務器、反向代理、訪問控制等功能。nginx

 

2、Lua的優勢git

Lua是一種輕量級、可嵌入式的腳本語言,這樣能夠很是容易的嵌入到其餘語言中使用。另外Lua提供了協程併發,即以同步調用的方式進行異步執行,從而實現併發,比起回調機制的併發來講代碼更容易編寫和理解,排查問題也會容易。Lua還提供了閉包機制,函數能夠做爲First Class Value 進行參數傳遞,另外其實現了標記清除垃圾收集。github

由於Lua的小巧輕量級,能夠在Nginx中嵌入Lua VM,請求的時候建立一個VM,請求結束的時候回收VM。web

 

3、什麼是ngx_luaredis

ngx_lua是Nginx的一個模塊,將Lua嵌入到Nginx中,從而可使用Lua來編寫腳本,這樣就可使用Lua編寫應用腳本,部署到Nginx中運行,即Nginx變成了一個Web容器;這樣開發人員就可使用Lua語言開發高性能Web應用了。

ngx_lua提供了與Nginx交互的不少的API,對於開發人員來講只須要學習這些API就能夠進行功能開發,而對於開發web應用來講,若是接觸過Servlet的話,其開發和Servlet相似,無外乎就是知道接收請求、參數解析、功能處理、返回響應這幾步的API是什麼樣子的。

 

4、開發環境

咱們可使用OpenResty來搭建開發環境,OpenResty將Nginx核心、LuaJIT、許多有用的Lua庫和Nginx第三方模塊打包在一塊兒;這樣開發人員只須要安裝OpenResty,不須要了解Nginx核心和寫複雜的C/C++模塊就能夠,只須要使用Lua語言進行Web應用開發了。

如何安裝能夠參考《跟我學Nginx+Lua開發》。

 

5、OpenResty生態

OpenResty提供了一些經常使用的ngx_lua開發模塊:如

  lua-resty-memcached

  lua-resty-mysql

  lua-resty-redis

  lua-resty-dns

  lua-resty-limit-traffic

  lua-resty-template

這些模塊涉及到如mysql數據庫、redis、限流、模塊渲染等經常使用功能組件;另外也有不少第三方的ngx_lua組件供咱們使用,對於大部分應用場景來講如今生態環境中的組件已經足夠多了;若是不知足需求也能夠本身去寫來完成本身的需求。

 

6、場景

理論上可使用ngx_lua開發各類複雜的web應用,不過Lua是一種腳本/動態語言,不適合業務邏輯比較重的場景,適合小巧的應用場景,代碼行數保持在幾十行到幾千行。目前見到的一些應用場景:

web應用:會進行一些業務邏輯處理,甚至進行耗CPU的模板渲染,通常流程:mysql/redis/http獲取數據、業務處理、產生JSON/XML/模板渲染內容,好比京東的列表頁/商品詳情頁;

接入網關:實現如數據校驗前置、緩存前置、數據過濾、API請求聚合、AB測試、灰度發佈、降級、監控等功能,好比京東的交易大Nginx節點、無線部門正在開發的無線網關、單品頁統一服務、實時價格、動態服務;

Web防火牆:能夠進行IP/URL/UserAgent/Referer黑名單、限流等功能;

緩存服務器:能夠對響應內容進行緩存,減小到後端的請求,從而提高性能;

其餘:如靜態資源服務器、消息推送服務、縮略圖裁剪等。

 

2、基於Nginx+Lua的經常使用架構模式

1、負載均衡

 

如上圖,咱們首先經過LVS+HAProxy將流量轉發給核心Nginx 1和核心Nginx 2,即實現了流量的負載均衡,此處可使用如輪訓、一致性哈希等調度算法來實現負載的轉發;而後核心Nginx會根據請求特徵如「Host:item.jd.com」,轉發給相應的業務Nginx節點如單品頁Nginx 1。此處爲何分兩層呢?

一、核心Nginx層是無狀態的,能夠在這一層實現流量分組(內網和外網隔離、爬蟲和非爬蟲流量隔離)、內容緩存、請求頭過濾、故障切換(機房故障切換到其餘機房)、限流、防火牆等一些通用型功能;

二、業務Nginx如單品頁Nginx,能夠在在業務Nginx實現業務邏輯、或者反向代理到如Tomcat,在這一層能夠實現內容壓縮(放在這一層的目的是減小核心Nginx的CPU壓力,將壓力分散到各業務Nginx)、AB測試、降級;即這一層的Nginx跟業務有關聯,實現業務的一些通用邏輯。

無論是核心Nginx仍是業務Nginx,都應該是無狀態設計,能夠水平擴容。



 

業務Nginx通常會把請求直接轉發給後端的業務應用,如Tomcat、PHP,即將請求內部轉發到相應的業務應用;當有的Tomcat出現問題了,能夠在這一層摘掉;或者有的業務路徑變了在這一層進行rewrite;或者有的後端Tomcat壓力太大也能夠在這一層降級,減小對後端的衝擊;或者業務須要灰度發佈時也能夠在這一層Nginx上控制。

 

2、單機閉環

所謂單機閉環即全部想要的數據都能從本服務器直接獲取,在大多數時候無需經過網絡去其餘服務器獲取。



 

如上所示,主要有三種應用模式:

2.一、第一張圖應用場景是Nginx應用誰也不依賴,好比咱們的Cookie白名單應用,其目的是不在白名單中的Cookie將被清理,防止你們隨便將Cookie寫到jd.om根下;你們訪問http://www.jd.com時,會看到一個http://ccc.jd.com/cookie_check的請求用來清理Cookie的;對於這種應用很是簡單,不須要依賴數據源,直接單應用閉環便可。

 

2.二、第二張圖,是讀取本機文件系統,如靜態資源合併:好比訪問http://item.jd.com/1856584.html,查看源碼會發現【<link type="text/css" rel="stylesheet" href="//misc.360buyimg.com/jdf/1.0.0/unit/??ui-base/1.0.0/ui-base.css,shortcut/2.0.0/shortcut.css,global-header/1.0.0/global-header.css,myjd/2.0.0/myjd.css,nav/2.0.0/nav.css,shoppingcart/2.0.0/shoppingcart.css,global-footer/1.0.0/global-footer.css,service/1.0.0/service.css"/>】這種請求,即多個請求合併爲一個發給服務端,服務端進行了文件資源的合併;


 

目前有成熟的Nginx模塊如nginx-http-concat進行靜態資源合併;由於咱們使用了OpenResty,那麼咱們徹底可使用Lua編寫程序實現該功能,好比已經有人寫了nginx-lua-static-merger來實現這個功能。

 

還一些業務型應用場景以下圖所示


 

商品頁面是由商品框架和其餘維度的頁面片斷(麪包屑、相關分類、商家信息、規格參數、商品詳情)組成;或者首頁是由首頁框架和一些頁面片斷(分類、輪播圖、樓層一、樓層N)組成;分維度是由於不一樣的維度是獨立變化的。對於這種靜態內容可是須要進行框架內容嵌入的方式,Nginx自帶的SSI(Server Side Include)能夠很輕鬆的完成;也可使用Lua程序更靈活的完成(讀取框架、讀取頁面片斷、合併輸出)。

 

好比商品頁面的架構咱們能夠這樣:


 

首先接收到商品變動消息,商品頁面同步Worker會根據消息維度生成相關的頁面推送到Nginx服務器;Nginx應用再經過SSI輸出。目前京東商品詳情頁沒有再採用這種架構,具體架構能夠參考《構建需求響應式億級商品詳情頁》。

 

對於首頁的架構是相似的,由於其特色(框架變化少,樓層變化較頻繁)和個性化的要求,樓層通常實現爲異步加載。

 

2.三、 第三張圖和第二張圖的不一樣處是再也不直接讀取文件系統,而是讀取本機的Redis或者Redis集羣或者如SSDB這種持久化存儲或者其餘存儲系統都是能夠的,好比直接說的商品頁面可使用SSDB進行存儲實現。文件系統一個很大的問題是當多臺服務器時須要Worker去寫多臺服務器,而這個過程可使用SSDB的主從實現。



 
此處能夠看到,無論是圖二仍是圖三架構,都須要Worker去進行數據推送;假設本機數據丟了可怎麼辦?所以實際大部分應用不會是徹底單機閉環的,而是會採用以下架構:

 





   

即首先讀本機,若是沒數據會回源到相應的Web應用從數據源拉取原始數據進行處理。這種架構的大部分場景本機均可以命中數據,只有不多一部分狀況會回源到Web應用。

 

如京東的實時價格/動態服務就是採用相似架構。

 

3、分佈式閉環

單機閉環會遇到以下兩個主要問題: 一、數據不一致問題(好比沒有采用主從架構致使不一樣服務器數據不一致);二、遇到存儲瓶頸(磁盤或者內存遇到了天花板)。

解決數據不一致的比較好的辦法是採用主從或者分佈式集中存儲;而遇到存儲瓶頸就須要進行按照業務鍵進行分片,將數據分散到多臺服務器。

 

如採用以下架構,按照尾號將內容分佈到多臺服務器。


 

即第一步先讀取分佈式存儲(JIMDB是京東的一個分佈式緩存/存儲系統,相似於Redis);若是不命中則回源到Tomcat集羣(其會調用數據庫、服務總線獲取相關數據)來獲取相關數據。能夠參考《構建需求響應式億級商品詳情頁》來獲取更詳細的架構實現。

 

JIMDB集羣會進行多機房主從同步,各自機房讀取本身機房的從JIMDB集羣,以下圖


 

 

4、接入網關

接入網關也能夠叫作接入層,即接收到流量的入口,在入口咱們能夠進行以下事情:


 

4.1、核心接入Nginx會作以下事情:

一、動態負載均衡;一、普通流量走一致性哈希,提高命中率;熱點流量走輪訓減小單服務器壓力;二、根據請求特徵將流量分配到不一樣分組並限流(爬蟲、或者流量大的IP);三、動態流量(動態增長upstream或者減小upstream或者動態負載均衡)可使用balancer_by_lua或者微博開源的upsync;

二、防DDOS攻擊限流:能夠將請求日誌推送到實時計算集羣,而後將須要限流的IP推送到核心Nginx進行限流;

三、非法請求過濾:好比應該有Referer卻沒有,或者應該帶着Cookie卻沒有Cookie;

四、請求聚合:好比請求的是http://c.3.cn/proxy?methods=a,b,c,核心接入Nginx會在服務端把Nginx併發的請求並把結果聚合而後一次性吐出;

五、請求頭過濾:有些業務是不須要請求頭的,所以能夠在往業務Nginx轉發時把這些數據過濾掉;

六、緩存服務:使用Nginx Proxy Cache實現內容頁面的緩存;

 

4.2、業務Nginx會作以下事情:

一、緩存:對於讀服務會使用大量的緩存來提高性能,咱們在設計時主要有以下緩存應用:首先讀取Nginx本地緩存  Shared Dict或者Nginx Proxy Cache,若是有直接返回內容給用戶;若是本地緩存不命中,則會讀取分佈式緩存如Redis,若是有直接返回;若是仍是不命中則回源到Tomcat應用讀取DB或調用服務獲取數據。另外咱們會按照維度進行數據的緩存。

二、業務邏輯:咱們會進行一些數據校驗/過濾邏輯前置(如商品ID必須是數字)、業務邏輯前置(獲取原子數據,而後在Nginx上寫業務邏輯)。

三、細粒度限流:按照接口特徵和接口吞吐量來實現動態限流,好比後端服務快扛不住了,那咱們就須要進行限流,被限流的請求做爲降級請求處理;經過lua-resty-limit-traffic能夠經過編程實現更靈活的降級邏輯,如根據用戶、根據URL等等各類規則,如降級了是讓用戶請求等待(好比sleep 100ms,這樣用戶請求就慢下來了,可是服務仍是可用)仍是返回降級內容。

四、降級:降級主要有兩種:主動降級和被動降級;如請求量太大扛不住了,那咱們須要主動降級;如後端掛了或者被限流了或者後端超時了,那咱們須要被動降級。降級方案能夠是:一、返回默認數據如庫存默認有貨;二、返回靜態頁如預先生成的靜態頁;三、部分用戶降級,告訴部分用戶等待下再操做;四、直接降級,服務沒數據,好比商品頁面的規格參數不展現;五、只降級回源服務,便可以讀取緩存的數據返回,實現部分可用,可是不會回源處理;

五、AB測試/灰度發佈:好比要上一個新的接口,能夠經過在業務Nginx經過Lua寫複雜的業務規則實現不一樣的人看到不一樣的版本。

六、服務質量監控:咱們能夠記錄請求響應時間、緩存響應時間、反向代理服務響應時間來詳細瞭解到底哪塊服務慢了;另外記錄非200狀態碼錯誤來了解服務的可用率。

 

京東的交易大Nginx節點、無線部門正在開發的無線Nginx網關、和單品頁統一服務都是接入網關的實踐,而單品頁統一服務架構能夠參考《京東商品詳情頁服務閉環實踐》。

 

5、Web應用

此處所說的Web應用指的是頁面模板渲染類型應用或者API服務類型應用;好比京東列表頁/商品詳情頁就是一個模板渲染類型的應用,核心業務邏輯都是使用Lua寫的,部署到Nginx容器。目前核心業務代碼行數有5000多行,模板頁面有2000多行,涉及到大量的計算邏輯,性能數據能夠參考《構建需求響應式億級商品詳情頁》。



 

總體處理過程和普通Web應用沒什麼區別:首先接收請求並進行解析;而後讀取JIMDB集羣數據、若是沒有則回源到Tomcat獲取;而後進行業務邏輯處理;渲染模板;將響應內容返回給用戶。

 

----------------

更新下Centos上簡單的按照操做做爲參考

````

sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
sudo yum install openresty

/sbin/service openresty start

sudo openresty -p /opt/my-fancy-app/

````

[openresty官網連接](http://openresty.org/cn/linux-packages.html)

-------------- 

 

3、如何使用Nginx+Lua開發Web應用

 

開發一個Web應用咱們須要從項目搭建、功能開發、項目部署幾個層面完成。

 

3.1、項目搭建 

Java代碼  
  1. /export/App/nginx-app   
  2.  -------bin(腳本)   
  3.  ------------start.sh   
  4.  ------------stop.sh   
  5.  -------config(配置文件)   
  6.  ------------nginx.conf   
  7.  ------------domain   
  8.  ----------------nginx_product.conf   
  9.  ------------resources.properties   
  10.  -------lua(業務代碼)   
  11.  ------------init.lua   
  12.  ------------product_controller.lua   
  13.  -------template(模板)   
  14.  --------------prodoct.html   
  15.  -------lualib(公共Lua庫)   
  16.  ------------jd   
  17.  ----------------product_util.lua   
  18.  ----------------product_data.lua   
  19.  ------------resty   
  20.  ----------------redis.lua   
  21.  ----------------template.lua  
/export/App/nginx-app
 -------bin(腳本)
 ------------start.sh
 ------------stop.sh
 -------config(配置文件)
 ------------nginx.conf
 ------------domain
 ----------------nginx_product.conf
 ------------resources.properties
 -------lua(業務代碼)
 ------------init.lua
 ------------product_controller.lua
 -------template(模板)
 --------------prodoct.html
 -------lualib(公共Lua庫)
 ------------jd
 ----------------product_util.lua
 ----------------product_data.lua
 ------------resty
 ----------------redis.lua
 ----------------template.lua

  

 整個項目結構從啓停腳本、配置文件、公共組件、業務代碼、模板代碼幾塊進行劃分。

 

1、啓停腳本

啓停腳本放在項目目錄/export/App/nginx-app/bin/下。

start.sh是啓動和更新腳本,即若是nginx沒有啓動則啓動起來,不然reload: 

Java代碼  
  1. if nginx沒啓動 then   
  2.   sudo /export/servers/nginx/sbin/nginx  -t -c /export/App/nginx-app/config/nginx.conf   
  3.   sudo /export/servers/nginx/sbin/nginx  -c /export/App/nginx-app/config/nginx.conf   
  4. else  
  5.   sudo /export/servers/nginx/sbin/nginx  -t   
  6.   sudo /export/servers/nginx/sbin/nginx  -s reload   
  7. end    
if nginx沒啓動 then
  sudo /export/servers/nginx/sbin/nginx  -t -c /export/App/nginx-app/config/nginx.conf
  sudo /export/servers/nginx/sbin/nginx  -c /export/App/nginx-app/config/nginx.conf
else
  sudo /export/servers/nginx/sbin/nginx  -t
  sudo /export/servers/nginx/sbin/nginx  -s reload
end  

stop.sh是中止Nginx腳本: 

Java代碼  
  1. sudo /export/servers/nginx/sbin/nginx  -s quit   
sudo /export/servers/nginx/sbin/nginx  -s quit 

 

2、配置文件

配置文件放在/export/App/nginx-app/config目錄下,包括了nginx.conf配置文件、nginx項目配置文件和資源配置文件。

 

nginx.confg配置文件  

Java代碼  
  1. worker_processes  1;   
  2. events {   
  3.     worker_connections  1024;   
  4. }   
  5. http {   
  6.    include       mime.types;   
  7.    default_type  text/html;   
  8.    #gzip相關   
  9.    #超時時間   
  10.    #日誌格式   
  11.    #反向代理配置   
  12.   
  13.    #lua依賴路徑   
  14.    lua_package_path  "/export/App/nginx-app/lualib/?.lua;;";   
  15.    lua_package_cpath  "/export/App/nginx-app/lualib/?.so;;";   
  16.   
  17.    #server配置   
  18.    include /export/App/nginx-app/config/domains/*;   
  19.   
  20.    #初始化腳本   
  21.    init_by_lua_file "/export/App/nginx-app/lua/init.lua";   
  22. }   
worker_processes  1;
events {
    worker_connections  1024;
}
http {
   include       mime.types;
   default_type  text/html;
   #gzip相關
   #超時時間
   #日誌格式
   #反向代理配置

   #lua依賴路徑
   lua_package_path  "/export/App/nginx-app/lualib/?.lua;;";
   lua_package_cpath  "/export/App/nginx-app/lualib/?.so;;";

   #server配置
   include /export/App/nginx-app/config/domains/*;

   #初始化腳本
   init_by_lua_file "/export/App/nginx-app/lua/init.lua";
} 

對於nginx.conf會進行一些通用的配置,如工做進程數、超時時間、壓縮、日誌格式、反向代理等相關配置;另外須要指定以下配置:

lua_package_path、lua_package_cpath指定咱們依賴的通用Lua庫從哪裏加載;

include /export/App/nginx-app/config/domains/*:用於加載server相關的配置,此處經過*能夠在一個nginx下指定多個server配置;

init_by_lua_file "/export/App/nginx-app/lua/init.lua":執行項目的一些初始化配置,好比加載配置文件。

 

nginx項目配置文件

/export/App/nginx-app/config/domains/nginx_product.conf用於配置當前web應用的一些server相關的配置: 

Java代碼  
  1. #upstream   
  2. upstream item_http_upstream {   
  3.     server 192.168.1.1 max_fails=2 fail_timeout=30s weight=5;   
  4.     server 192.168.1.2 max_fails=2 fail_timeout=30s weight=5;   
  5. }   
  6. #緩存   
  7. lua_shared_dict item_local_shop_cache 600m;   
  8. server {   
  9.      listen                   80;   
  10.      server_name              item.jd.com item.jd.hk;   
  11.      #模板文件從哪加載   
  12.     set $template_root "/export/App/nginx-app/template ";   
  13.      #url映射   
  14.         location ~* "^/product/(\d+)\.html$" {   
  15.             rewrite /product/(.*)    http://item.jd.com/$1 permanent;   
  16.         }   
  17.     location ~* "^/(\d{6,12})\.html$" {   
  18.             default_type text/html;   
  19.             charset gbk;   
  20.             lua_code_cache on;   
  21.             content_by_lua_file "/export/App/nginx-app/lua/product_controller.lua";   
  22.         }   
  23. }   
#upstream
upstream item_http_upstream {
    server 192.168.1.1 max_fails=2 fail_timeout=30s weight=5;
    server 192.168.1.2 max_fails=2 fail_timeout=30s weight=5;
}
#緩存
lua_shared_dict item_local_shop_cache 600m;
server {
     listen                   80;
     server_name              item.jd.com item.jd.hk;
     #模板文件從哪加載
    set $template_root "/export/App/nginx-app/template ";
     #url映射
        location ~* "^/product/(\d+)\.html$" {
            rewrite /product/(.*)    http://item.jd.com/$1 permanent;
        }
	location ~* "^/(\d{6,12})\.html$" {
            default_type text/html;
            charset gbk;
            lua_code_cache on;
            content_by_lua_file "/export/App/nginx-app/lua/product_controller.lua";
        }
} 

咱們須要指定如upstream、共享字典配置、server配置、模板文件從哪加載、url映射,好比咱們訪問http://item.jd.com/1856584.html將交給/export/App/nginx-app/lua/product_controller.lua處理;也就是說咱們項目的入口就有了。

 

資源配置文件resources.properties包含了咱們的一些好比開關的配置、緩存服務器地址的配置等等。

 

3、業務代碼

/export/App/nginx-app/lua/目錄裏存放了咱們的lua業務代碼,init.lua用於讀取如resources.properties來進行一些項目初始化;product_controller.lua能夠當作Java Web中的Servlet,接收、處理、響應用戶請求。

 

4、模板

模板文件放在/export/App/nginx-app/template/目錄下,使用相應的模板引擎進行編寫頁面模板,而後渲染輸出。

 

5、公共Lua

存放了一些如redis、template等相關的公共Lua庫,還有一些咱們項目中通用的工具庫如product_util.lua。

 

到此一個簡單的項目的結構就介紹完了,對於開發一個項目來講還會牽扯到分模塊等工做,不過對於咱們這種Lua應用來講,建議不要過分抽象,儘可能小巧便可。

 

3.2、功能開發

接下來就須要使用相應的API來實現咱們的業務了,好比product_controller.lua:

Java代碼  
  1. --加載Lua模塊庫   
  2. local template = require("resty.template")     
  3. --一、獲取請求參數中的商品ID   
  4. local skuId = ngx.req.get_uri_args()["skuId"];   
  5. --二、調用相應的服務獲取數據   
  6. local data = api.getData(skuId)   
  7.   
  8. --三、渲染模板   
  9. local func = template.compile("product.html")     
  10. local content = func(data)     
  11. --四、經過ngx API輸出內容     
  12. ngx.say(content)     
--加載Lua模塊庫
local template = require("resty.template")  
--一、獲取請求參數中的商品ID
local skuId = ngx.req.get_uri_args()["skuId"];
--二、調用相應的服務獲取數據
local data = api.getData(skuId)

--三、渲染模板
local func = template.compile("product.html")  
local content = func(data)  
--四、經過ngx API輸出內容  
ngx.say(content)   

開發完成後將項目部署到測試環境,執行start.sh啓動nginx而後進行測試。

詳細的開發過程和API的使用,請參考《跟我學Nginx+Lua開發》。此處不作具體編碼實現。

 

參考源碼:Nginx+Lua(OpenResty) HelloWorld

 

4、基於Nginx+Lua的經常使用功能總結

到此咱們對於Nginx開發已經有了一個總體的認識,對於Nginx粘合Lua來開發應用能夠說是一把鋒利的瑞士軍刀,能夠幫咱們很容易的解決不少問題,能夠開發Web應用、接入網關、API網關、消息推送、日誌採集等應用,不過我的認爲適合開發業務邏輯單1、核心代碼行數較少的應用,不適合業務邏輯複雜、功能繁多的業務型或者企業級應用;最後咱們總結下基於Nginx+Lua的經常使用架構模式中一些常見實踐和場景:

  動態負載均衡;

  防火牆(DDOS、IP/URL/UserAgent/Referer黑名單、防盜鏈等)

  限流;

  降級;

  AB測試/灰度發佈;

  多級緩存模式;

  服務端請求聚合;

  服務質量監控。

 

一些問題

一、在開發nginx應用時使用UTF-8編碼能夠減去不少麻煩;

二、GBK轉碼解碼時使用GB18030,不然一些特殊字符會出現亂碼;

三、cjson庫對於如\uab1這種錯誤的unicode轉碼會失敗,可使用純Lua編寫的dkjson;

四、社區版nginx不支持upstream的域名動態解析;能夠考慮proxy_pass http://p.3.local/prices/mgets$is_args$args,而後配合resolver來實現;或者在lua中進行http調用;若是DNS遇到性能瓶頸能夠考慮在本機部署如dnsmasq來緩存;或者考慮使用balancer_by_lua功能實現動態upstream;

五、爲響應添加處理服務器IP的響應頭,方便定位問題;

六、根據業務設置合理的超時時間;

七、走CDN的業務當發生錯誤時返回的500/503/302/301等非正常響應不要設置緩存。

 

5、參考文資料

深刻 Nginx:咱們是如何爲性能和規模作設計的

  http://blog.jobbole.com/88766/

Nginx變量漫談/配置指令的執行順序

  http://blog.sina.com.cn/openresty

ngx_lua文檔

  https://github.com/openresty/lua-nginx-module#readme

OpenResty最佳實踐

  https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/brief.html

跟我學Nginx+Lua開發

  http://jinnianshilongnian.iteye.com/blog/2190344

構建需求響應式億級商品詳情頁

  http://jinnianshilongnian.iteye.com/blog/2235572

京東商品詳情頁服務閉環實踐

  http://jinnianshilongnian.iteye.com/blog/2258111 

Upsync:微博開源基於Nginx容器動態流量管理方案

  http://toutiao.com/a6254279391729139970

相關文章
相關標籤/搜索