參考學習目錄:https://www.iteye.com/blog/jinnianshilongnian-2190344
在互聯(lián)網公司,Nginx可以說是標配組件,但是主要場景還是負載均衡街图、反向代理、代理緩存赞庶、限流等場景;而把Nginx作為一個Web容器使用的還不是那么廣泛。Nginx的高性能是大家公認的,而Nginx開發(fā)主要是以C/C++模塊的形式進行淤刃,整體學習和開發(fā)成本偏高;如果有一種簡單的語言來實現(xiàn)Web應用的開發(fā)吱型,那么Nginx絕對是把好的瑞士軍刀逸贾;目前Nginx團隊也開始意識到這個問題,開發(fā)了nginxScript:可以在Nginx中使用JavaScript進行動態(tài)配置一些變量和動態(tài)腳本執(zhí)行津滞;而目前市面上用的非常成熟的擴展是由章亦春將Lua和Nginx粘合的ngx_lua模塊铝侵,并且將Nginx核心、LuaJIT触徐、ngx_lua模塊咪鲜、許多有用的Lua庫和常用的第三方Nginx模塊組合在一起成為OpenResty,這樣開發(fā)人員就可以安裝OpenResty撞鹉,使用Lua編寫腳本疟丙,然后部署到Nginx Web容器中運行。從而非常輕松就能開發(fā)出高性能的Web服務鸟雏。
接下來我們就認識下Nginx隆敢、Lua、ngx_lua模塊和ngx_lua到底能開發(fā)哪些類型的web應用崔慧。
一拂蝎、ngx_lua簡介
1****、Nginx****優(yōu)點
Nginx設計為一個主進程多個工作進程的工作模式惶室,每個進程是單線程來處理多個連接温自,而且每個工作進程采用了非阻塞I/O來處理多個連接玄货,從而減少了線程上下文切換,從而實現(xiàn)了公認的高性能悼泌、高并發(fā)松捉;因此在生成環(huán)境中會通過把CPU綁定給Nginx工作進程從而提升其性能;另外因為單線程工作模式的特點馆里,內存占用就非常少了隘世。
Nginx更改配置重啟速度非常快鸠踪,可以毫秒級丙者,而且支持不停止Nginx進行升級Nginx版本、動態(tài)重載Nginx配置营密。
Nginx模塊也是非常多械媒,功能也很強勁,不僅可以作為http負載均衡评汰,Nginx發(fā)布1.9.0版本還支持TCP負載均衡纷捞,還可以很容易的實現(xiàn)內容緩存、web服務器被去、反向代理主儡、訪問控制等功能。
2****惨缆、Lua****的優(yōu)點
Lua是一種輕量級缀辩、可嵌入式的腳本語言,這樣可以非常容易的嵌入到其他語言中使用踪央。另外Lua提供了協(xié)程并發(fā)臀玄,即以同步調用的方式進行異步執(zhí)行,從而實現(xiàn)并發(fā)畅蹂,比起回調機制的并發(fā)來說代碼更容易編寫和理解健无,排查問題也會容易。Lua還提供了閉包機制液斜,函數(shù)可以作為First Class Value 進行參數(shù)傳遞累贤,另外其實現(xiàn)了標記清除垃圾收集。
因為Lua的小巧輕量級少漆,可以在Nginx中嵌入Lua VM臼膏,請求的時候創(chuàng)建一個VM,請求結束的時候回收VM示损。
3****渗磅、什么是ngx_lua
ngx_lua是Nginx的一個模塊,將Lua嵌入到Nginx中,從而可以使用Lua來編寫腳本始鱼,這樣就可以使用Lua編寫應用腳本仔掸,部署到Nginx中運行,即Nginx變成了一個Web容器医清;這樣開發(fā)人員就可以使用Lua語言開發(fā)高性能Web應用了起暮。
ngx_lua提供了與Nginx交互的很多的API,對于開發(fā)人員來說只需要學習這些API就可以進行功能開發(fā)会烙,而對于開發(fā)web應用來說负懦,如果接觸過Servlet的話,其開發(fā)和Servlet類似柏腻,無外乎就是知道接收請求纸厉、參數(shù)解析、功能處理葫盼、返回響應這幾步的API是什么樣子的。
4****村斟、開發(fā)環(huán)境
我們可以使用OpenResty來搭建開發(fā)環(huán)境贫导,OpenResty將Nginx核心、LuaJIT蟆盹、許多有用的Lua庫和Nginx第三方模塊打包在一起孩灯;這樣開發(fā)人員只需要安裝OpenResty,不需要了解Nginx核心和寫復雜的C/C++模塊就可以逾滥,只需要使用Lua語言進行Web應用開發(fā)了峰档。
如何安裝可以參考《跟我學Nginx+Lua開發(fā)》。
5****寨昙、OpenResty****生態(tài)
OpenResty提供了一些常用的ngx_lua開發(fā)模塊:如
lua-resty-memcached
lua-resty-mysql
lua-resty-redis
lua-resty-dns
lua-resty-limit-traffic
lua-resty-template
這些模塊涉及到如mysql數(shù)據(jù)庫讥巡、redis、限流舔哪、模塊渲染等常用功能組件欢顷;另外也有很多第三方的ngx_lua組件供我們使用,對于大部分應用場景來說現(xiàn)在生態(tài)環(huán)境中的組件已經足夠多了捉蚤;如果不滿足需求也可以自己去寫來完成自己的需求抬驴。
6****、場景
理論上可以使用ngx_lua開發(fā)各種復雜的web應用缆巧,不過Lua是一種腳本/動態(tài)語言布持,不適合業(yè)務邏輯比較重的場景,適合小巧的應用場景陕悬,代碼行數(shù)保持在幾十行到幾千行题暖。目前見到的一些應用場景:
web****應用:會進行一些業(yè)務邏輯處理,甚至進行耗CPU的模板渲染,一般流程:mysql/redis/http獲取數(shù)據(jù)芙委、業(yè)務處理逞敷、產生JSON/XML/模板渲染內容,比如京東的列表頁/商品詳情頁灌侣;
接入網關:實現(xiàn)如數(shù)據(jù)校驗前置推捐、緩存前置、數(shù)據(jù)過濾侧啼、API請求聚合牛柒、AB測試、灰度發(fā)布痊乾、降級皮壁、監(jiān)控等功能,比如京東的交易大Nginx節(jié)點哪审、無線部門正在開發(fā)的無線網關蛾魄、單品頁統(tǒng)一服務、實時價格湿滓、動態(tài)服務滴须;
Web****防火墻:可以進行IP/URL/UserAgent/Referer黑名單、限流等功能叽奥;
緩存服務器:可以對響應內容進行緩存扔水,減少到后端的請求,從而提升性能朝氓;
其他:如靜態(tài)資源服務器魔市、消息推送服務、縮略圖裁剪等赵哲。
二待德、基于Nginx+Lua的常用架構模式
1****、負載均衡
如上圖枫夺,我們首先通過LVS+HAProxy將流量轉發(fā)給核心Nginx 1和核心Nginx 2磅网,即實現(xiàn)了流量的負載均衡,此處可以使用如輪訓筷屡、一致性哈希等調度算法來實現(xiàn)負載的轉發(fā)涧偷;然后核心Nginx會根據(jù)請求特征如“Host:item.jd.com”,轉發(fā)給相應的業(yè)務Nginx節(jié)點如單品頁Nginx 1毙死。此處為什么分兩層呢燎潮?
1、核心Nginx層是無狀態(tài)的扼倘,可以在這一層實現(xiàn)流量分組(內網和外網隔離确封、爬蟲和非爬蟲流量隔離)除呵、內容緩存、請求頭過濾爪喘、故障切換(機房故障切換到其他機房)颜曾、限流、防火墻等一些通用型功能秉剑;
2泛豪、業(yè)務Nginx如單品頁Nginx,可以在在業(yè)務Nginx實現(xiàn)業(yè)務邏輯侦鹏、或者反向代理到如Tomcat诡曙,在這一層可以實現(xiàn)內容壓縮(放在這一層的目的是減少核心Nginx的CPU壓力,將壓力分散到各業(yè)務Nginx)略水、AB測試价卤、降級;即這一層的Nginx跟業(yè)務有關聯(lián)渊涝,實現(xiàn)業(yè)務的一些通用邏輯慎璧。
不管是核心Nginx還是業(yè)務Nginx,都應該是無狀態(tài)設計跨释,可以水平擴容胸私。
業(yè)務Nginx一般會把請求直接轉發(fā)給后端的業(yè)務應用,如Tomcat煤傍、PHP盖文,即將請求內部轉發(fā)到相應的業(yè)務應用嘱蛋;當有的Tomcat出現(xiàn)問題了蚯姆,可以在這一層摘掉;或者有的業(yè)務路徑變了在這一層進行rewrite洒敏;或者有的后端Tomcat壓力太大也可以在這一層降級龄恋,減少對后端的沖擊;或者業(yè)務需要灰度發(fā)布時也可以在這一層Nginx上控制凶伙。
2****郭毕、單機閉環(huán)
所謂單機閉環(huán)即所有想要的數(shù)據(jù)都能從本服務器直接獲取,在大多數(shù)時候無需通過網絡去其他服務器獲取函荣。
如上所示显押,主要有三種應用模式:
2.1、第一張圖應用場景是Nginx應用誰也不依賴傻挂,比如我們的Cookie白名單應用乘碑,其目的是不在白名單中的Cookie將被清理,防止大家隨便將Cookie寫到jd.om根下金拒;大家訪問http://www.jd.com時兽肤,會看到一個http://ccc.jd.com/cookie_check的請求用來清理Cookie的;對于這種應用非常簡單,不需要依賴數(shù)據(jù)源资铡,直接單應用閉環(huán)即可电禀。
2.2、第二張圖笤休,是讀取本機文件系統(tǒng)尖飞,如靜態(tài)資源合并:比如訪問http://item.jd.com/1856584.html,查看源碼會發(fā)現(xiàn)【<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"/>】這種請求宛官,即多個請求合并為一個發(fā)給服務端葫松,服務端進行了文件資源的合并;
目前有成熟的Nginx模塊如nginx-http-concat進行靜態(tài)資源合并底洗;因為我們使用了OpenResty腋么,那么我們完全可以使用Lua編寫程序實現(xiàn)該功能,比如已經有人寫了nginx-lua-static-merger來實現(xiàn)這個功能亥揖。
還一些業(yè)務型應用場景如下圖所示
商品頁面是由商品框架和其他維度的頁面片段(面包屑珊擂、相關分類、商家信息费变、規(guī)格參數(shù)摧扇、商品詳情)組成;或者首頁是由首頁框架和一些頁面片段(分類挚歧、輪播圖扛稽、樓層1、樓層N)組成滑负;分維度是因為不同的維度是獨立變化的在张。對于這種靜態(tài)內容但是需要進行框架內容嵌入的方式,Nginx自帶的SSI(Server Side Include)可以很輕松的完成矮慕;也可以使用Lua程序更靈活的完成(讀取框架帮匾、讀取頁面片段、合并輸出)痴鳄。
比如商品頁面的架構我們可以這樣:
首先接收到商品變更消息瘟斜,商品頁面同步Worker會根據(jù)消息維度生成相關的頁面推送到Nginx服務器;Nginx應用再通過SSI輸出痪寻。目前京東商品詳情頁沒有再采用這種架構螺句,具體架構可以參考《構建需求響應式億級商品詳情頁》。
對于首頁的架構是類似的橡类,因為其特點(框架變化少蛇尚,樓層變化較頻繁)和個性化的要求,樓層一般實現(xiàn)為異步加載猫态。
2.3佣蓉、 第三張圖和第二張圖的不同處是不再直接讀取文件系統(tǒng)披摄,而是讀取本機的Redis或者Redis集群或者如SSDB這種持久化存儲或者其他存儲系統(tǒng)都是可以的,比如直接說的商品頁面可以使用SSDB進行存儲實現(xiàn)勇凭。文件系統(tǒng)一個很大的問題是當多臺服務器時需要Worker去寫多臺服務器疚膊,而這個過程可以使用SSDB的主從實現(xiàn)。
**
即首先讀本機,如果沒數(shù)據(jù)會回源到相應的Web應用從數(shù)據(jù)源拉取原始數(shù)據(jù)進行處理蘸吓。這種架構的大部分場景本機都可以命中數(shù)據(jù)善炫,只有很少一部分情況會回源到Web應用。
如京東的實時價格/動態(tài)服務就是采用類似架構库继。
3****箩艺、分布式閉環(huán)
單機閉環(huán)會遇到如下兩個主要問題: 1、數(shù)據(jù)不一致問題(比如沒有采用主從架構導致不同服務器數(shù)據(jù)不一致)宪萄;2艺谆、遇到存儲瓶頸(磁盤或者內存遇到了天花板)。
解決數(shù)據(jù)不一致的比較好的辦法是采用主從或者分布式集中存儲拜英;而遇到存儲瓶頸就需要進行按照業(yè)務鍵進行分片静汤,將數(shù)據(jù)分散到多臺服務器。
如采用如下架構居凶,按照尾號將內容分布到多臺服務器虫给。
即第一步先讀取分布式存儲(JIMDB是京東的一個分布式緩存/存儲系統(tǒng),類似于Redis)排监;如果不命中則回源到Tomcat集群(其會調用數(shù)據(jù)庫狰右、服務總線獲取相關數(shù)據(jù))來獲取相關數(shù)據(jù)杰捂∮叽玻可以參考《構建需求響應式億級商品詳情頁》來獲取更詳細的架構實現(xiàn)。
JIMDB集群會進行多機房主從同步嫁佳,各自機房讀取自己機房的從JIMDB集群挨队,如下圖
4****、接入網關
接入網關也可以叫做接入層蒿往,即接收到流量的入口盛垦,在入口我們可以進行如下事情:
4.1****、核心接入Nginx****會做如下事情:
1瓤漏、動態(tài)負載均衡腾夯;1颊埃、普通流量走一致性哈希,提升命中率蝶俱;熱點流量走輪訓減少單服務器壓力班利;2、根據(jù)請求特征將流量分配到不同分組并限流(爬蟲榨呆、或者流量大的IP)罗标;3、動態(tài)流量(動態(tài)增加upstream或者減少upstream或者動態(tài)負載均衡)可以使用balancer_by_lua或者微博開源的upsync积蜻;
2闯割、防DDOS攻擊限流:可以將請求日志推送到實時計算集群,然后將需要限流的IP推送到核心Nginx進行限流竿拆;
3宙拉、非法請求過濾:比如應該有Referer卻沒有,或者應該帶著Cookie卻沒有Cookie丙笋;
4鼓黔、請求聚合:比如請求的是http://c.3.cn/proxy?methods=a,b,c,核心接入Nginx會在服務端把Nginx并發(fā)的請求并把結果聚合然后一次性吐出不见;
5澳化、請求頭過濾:有些業(yè)務是不需要請求頭的,因此可以在往業(yè)務Nginx轉發(fā)時把這些數(shù)據(jù)過濾掉稳吮;
6缎谷、緩存服務:使用Nginx Proxy Cache實現(xiàn)內容頁面的緩存;
4.2****灶似、業(yè)務Nginx****會做如下事情:
1列林、緩存:對于讀服務會使用大量的緩存來提升性能,我們在設計時主要有如下緩存應用:首先讀取Nginx本地緩存 Shared Dict或者Nginx Proxy Cache酪惭,如果有直接返回內容給用戶希痴;如果本地緩存不命中,則會讀取分布式緩存如Redis春感,如果有直接返回砌创;如果還是不命中則回源到Tomcat應用讀取DB或調用服務獲取數(shù)據(jù)。另外我們會按照維度進行數(shù)據(jù)的緩存鲫懒。
2嫩实、業(yè)務邏輯:我們會進行一些數(shù)據(jù)校驗/過濾邏輯前置(如商品ID必須是數(shù)字)、業(yè)務邏輯前置(獲取原子數(shù)據(jù)窥岩,然后在Nginx上寫業(yè)務邏輯)甲献。
3、細粒度限流:按照接口特征和接口吞吐量來實現(xiàn)動態(tài)限流颂翼,比如后端服務快扛不住了晃洒,那我們就需要進行限流慨灭,被限流的請求作為降級請求處理;通過lua-resty-limit-traffic可以通過編程實現(xiàn)更靈活的降級邏輯球及,如根據(jù)用戶缘挑、根據(jù)URL等等各種規(guī)則,如降級了是讓用戶請求等待(比如sleep 100ms桶略,這樣用戶請求就慢下來了语淘,但是服務還是可用)還是返回降級內容。
4际歼、降級:降級主要有兩種:主動降級和被動降級惶翻;如請求量太大扛不住了,那我們需要主動降級鹅心;如后端掛了或者被限流了或者后端超時了吕粗,那我們需要被動降級。降級方案可以是:1旭愧、返回默認數(shù)據(jù)如庫存默認有貨颅筋;2、返回靜態(tài)頁如預先生成的靜態(tài)頁输枯;3议泵、部分用戶降級醉冤,告訴部分用戶等待下再操作抬纸;4、直接降級宇驾,服務沒數(shù)據(jù)瞳收,比如商品頁面的規(guī)格參數(shù)不展示碉京;5、只降級回源服務螟深,即可以讀取緩存的數(shù)據(jù)返回谐宙,實現(xiàn)部分可用,但是不會回源處理界弧;
5凡蜻、AB測試/灰度發(fā)布:比如要上一個新的接口,可以通過在業(yè)務Nginx通過Lua寫復雜的業(yè)務規(guī)則實現(xiàn)不同的人看到不同的版本夹纫。
6咽瓷、服務質量監(jiān)控:我們可以記錄請求響應時間设凹、緩存響應時間舰讹、反向代理服務響應時間來詳細了解到底哪塊服務慢了;另外記錄非200狀態(tài)碼錯誤來了解服務的可用率闪朱。
京東的交易大Nginx節(jié)點月匣、無線部門正在開發(fā)的無線Nginx網關钻洒、和單品頁統(tǒng)一服務都是接入網關的實踐,而單品頁統(tǒng)一服務架構可以參考《京東商品詳情頁服務閉環(huán)實踐》锄开。
5****素标、Web****應用
此處所說的Web應用指的是頁面模板渲染類型應用或者API服務類型應用;比如京東列表頁/商品詳情頁就是一個模板渲染類型的應用萍悴,核心業(yè)務邏輯都是使用Lua寫的头遭,部署到Nginx容器。目前核心業(yè)務代碼行數(shù)有5000多行癣诱,模板頁面有2000多行计维,涉及到大量的計算邏輯,性能數(shù)據(jù)可以參考《構建需求響應式億級商品詳情頁》撕予。
整體處理過程和普通Web應用沒什么區(qū)別:首先接收請求并進行解析鲫惶;然后讀取JIMDB集群數(shù)據(jù)、如果沒有則回源到Tomcat獲仁德铡欠母;然后進行業(yè)務邏輯處理;渲染模板吆寨;將響應內容返回給用戶赏淌。
三、如何使用Nginx+Lua開發(fā)Web應用
開發(fā)一個Web應用我們需要從項目搭建啄清、功能開發(fā)猜敢、項目部署幾個層面完成。
3.1****盒延、項目搭建
- /export/App/nginx-app
- -------bin(腳本)
- ------------start.sh
- ------------stop.sh
- -------config(配置文件)
- ------------nginx.conf
- ------------domain
- ----------------nginx_product.conf
- ------------resources.properties
- -------lua(業(yè)務代碼)
- ------------init.lua
- ------------product_controller.lua
- -------template(模板)
- --------------prodoct.html
- -------lualib(公共Lua庫)
- ------------jd
- ----------------product_util.lua
- ----------------product_data.lua
- ------------resty
- ----------------redis.lua
- ----------------template.lua
整個項目結構從啟停腳本缩擂、配置文件、公共組件添寺、業(yè)務代碼胯盯、模板代碼幾塊進行劃分。
1****计露、啟停腳本
啟停腳本放在項目目錄/export/App/nginx-app/bin/下博脑。
start.sh是啟動和更新腳本,即如果nginx沒有啟動則啟動起來票罐,否則reload:
- 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腳本:
- sudo /export/servers/nginx/sbin/nginx -s quit
2****叉趣、配置文件
配置文件放在/export/App/nginx-app/config目錄下,包括了nginx.conf配置文件该押、nginx項目配置文件和資源配置文件疗杉。
nginx.confg****配置文件
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會進行一些通用的配置,如工作進程數(shù)蚕礼、超時時間烟具、壓縮梢什、日志格式、反向代理等相關配置朝聋;另外需要指定如下配置:
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":執(zhí)行項目的一些初始化配置,比如加載配置文件言蛇。
nginx****項目配置文件
/export/App/nginx-app/config/domains/nginx_product.conf用于配置當前web應用的一些server相關的配置:
-
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****携龟、業(yè)務代碼
/export/App/nginx-app/lua/目錄里存放了我們的lua業(yè)務代碼,init.lua用于讀取如resources.properties來進行一些項目初始化勘高;product_controller.lua可以看成Java Web中的Servlet峡蟋,接收、處理华望、響應用戶請求蕊蝗。
4****、模板
模板文件放在/export/App/nginx-app/template/目錄下赖舟,使用相應的模板引擎進行編寫頁面模板蓬戚,然后渲染輸出。
5****宾抓、公共Lua****庫
存放了一些如redis子漩、template等相關的公共Lua庫,還有一些我們項目中通用的工具庫如product_util.lua石洗。
到此一個簡單的項目的結構就介紹完了幢泼,對于開發(fā)一個項目來說還會牽扯到分模塊等工作,不過對于我們這種Lua應用來說讲衫,建議不要過度抽象缕棵,盡量小巧即可。
3.2****、功能開發(fā)
接下來就需要使用相應的API來實現(xiàn)我們的業(yè)務了挥吵,比如product_controller.lua:
--加載Lua模塊庫
local template = require("resty.template")
--1重父、獲取請求參數(shù)中的商品ID
local skuId = ngx.req.get_uri_args()["skuId"];
--2花椭、調用相應的服務獲取數(shù)據(jù)
local data = api.getData(skuId)
--3忽匈、渲染模板
local func = template.compile("product.html")
local content = func(data)
--4、通過ngx API輸出內容
ngx.say(content)
開發(fā)完成后將項目部署到測試環(huán)境矿辽,執(zhí)行start.sh啟動nginx然后進行測試丹允。
詳細的開發(fā)過程和API的使用,請參考《跟我學Nginx+Lua開發(fā)》袋倔。此處不做具體編碼實現(xiàn)雕蔽。
參考源碼:Nginx+Lua(OpenResty) HelloWorld
四、基于Nginx+Lua的常用功能總結
到此我們對于Nginx開發(fā)已經有了一個整體的認識宾娜,對于Nginx粘合Lua來開發(fā)應用可以說是一把鋒利的瑞士軍刀批狐,可以幫我們很容易的解決很多問題,可以開發(fā)Web應用前塔、接入網關嚣艇、API網關、消息推送华弓、日志采集等應用食零,不過個人認為適合開發(fā)業(yè)務邏輯單一、核心代碼行數(shù)較少的應用寂屏,不適合業(yè)務邏輯復雜贰谣、功能繁多的業(yè)務型或者企業(yè)級應用;最后我們總結下基于Nginx+Lua的常用架構模式中一些常見實踐和場景:
** 動態(tài)負載均衡迁霎;**
** 防火墻(DDOS吱抚、IP/URL/UserAgent/Referer黑名單、防盜鏈等)考廉;**
** 限流频伤;**
** 降級;**
** AB測試/灰度發(fā)布芝此;**
** 多級緩存模式憋肖;**
** 服務端請求聚合;**
** 服務質量監(jiān)控婚苹。**
一些問題
1岸更、在開發(fā)nginx應用時使用UTF-8編碼可以減去很多麻煩;
2膊升、GBK轉碼解碼時使用GB18030怎炊,否則一些特殊字符會出現(xiàn)亂碼;
3、cjson庫對于如\uab1這種錯誤的unicode轉碼會失敗评肆,可以使用純Lua編寫的dkjson债查;
4、社區(qū)版nginx不支持upstream的域名動態(tài)解析瓜挽;可以考慮proxy_pass http://p.3.local/prices/mgetsargs盹廷,然后配合resolver來實現(xiàn);或者在lua中進行http調用久橙;如果DNS遇到性能瓶頸可以考慮在本機部署如dnsmasq來緩存俄占;或者考慮使用balancer_by_lua功能實現(xiàn)動態(tài)upstream;
5淆衷、為響應添加處理服務器IP的響應頭缸榄,方便定位問題;
6祝拯、根據(jù)業(yè)務設置合理的超時時間甚带;
7、走CDN的業(yè)務當發(fā)生錯誤時返回的500/503/302/301等非正常響應不要設置緩存佳头。