現(xiàn)在很多地方都使用nginx或者tengine進(jìn)行前端的負(fù)載均衡胎源,但單純使用nginx(tengine)不能完全滿足日常需求辜窑,所以攒驰,需要進(jìn)行適當(dāng)?shù)墓δ軘U(kuò)展吝岭,在以往只能是nginx c模塊開發(fā),這樣費(fèi)時(shí)費(fèi)力還難維護(hù)威蕉,對(duì)于中小型公司簡(jiǎn)直是一萬點(diǎn)傷害呢刁俭。幸運(yùn)的是有大神做了nginx的lua模塊,使得nginx(tengine)功能擴(kuò)展變得簡(jiǎn)單和易維護(hù)韧涨。
結(jié)合我們現(xiàn)在正在使用的例子牍戚,分幾篇文章和大家分享一下,nginx(tengine)和lua一起搭配使用的例子虑粥。
動(dòng)態(tài)后端
面對(duì)場(chǎng)景:
自動(dòng)化擴(kuò)容和縮容還有智能化運(yùn)維一直是我們努力實(shí)現(xiàn)的目標(biāo)如孝,但在傳統(tǒng)的nginx后端配置中,修改upstream的server配置是需要reload或者restart娩贷。對(duì)于應(yīng)用為長(zhǎng)鏈接第晰、流量大系統(tǒng),這會(huì)影響用戶體驗(yàn)彬祖。
具體做法是:
1.利用lua中 "lua_shared_dict"? 申請(qǐng)共享內(nèi)存空間茁瘦,這個(gè)內(nèi)存空間能被nginx(tengine)所有子進(jìn)程讀取储笑;
2.構(gòu)造API甜熔,讓其通過調(diào)用進(jìn)行修改共享內(nèi)存空間的值 ;
3.利用 proxy_pass 可使用變量特性及l(fā)ua指令 "set_by_lua" 動(dòng)態(tài)修改當(dāng)前proxy的值達(dá)到動(dòng)態(tài)效果。
簡(jiǎn)單代碼例子
1.申請(qǐng)共享內(nèi)存塊dyproxy
lua_shared_dict dyproxy 3m;
2.制造修改功能api突倍,host為key纺非,rip為后端ip
location ~ ^/DYPROXYSET {
default_type 'text/plain';
content_by_lua '
local dip = ngx.shared.dyproxy
local uri_args = ngx.req.get_uri_args()
if? uri_args["method"] == "add" then
if uri_args["domain"] == nil then
ngx.say("domain is null")
elseif uri_args["rip"] == nil? then
ngx.say("rip is null")
else
dip:set(uri_args["domain"],uri_args["rip"]) //設(shè)置domain:rip ,eg: xx.pcauto.com.cn:192.168.10.1|192.168.10.2
ngx.say("Set successfully : domain"..uri_args["domain"].."|rip"..uri_args["rip"])
end
elseif? uri_args["method"] == "del" then
if uri_args["domain"] == nil then
ngx.say("domain is null")
else
dip:delete(uri_args["domain"])
ngx.say("del successfully")
end
end
';
}
3.使用共享內(nèi)存的值達(dá)到動(dòng)態(tài)變量的效果
location ~ ^/testdyproxy {
default_type 'text/plain';
set_by_lua_file $dybackend conf/dyproxy.lua;
proxy_pass? ? ? ? http://$dybackend;
proxy_redirect? ? off;
proxy_set_header? Host? ? ? ? ? ? $host;
proxy_set_header? X-Real-IP? ? ? ? $remote_addr;
proxy_set_header? X-Forwarded-For? $proxy_add_x_forwarded_for;
proxy_connect_timeout 3;
proxy_read_timeout 10;
}
dyproxy.lua:
math.randomseed(tostring(os.time()):reverse():sub(1, 6))
local dip = ngx.shared.dyproxy
backend =? dip:get(ngx.var.host)
if backend == nil then
return "192.168.10.208:80"
end
local backendarr = loadstring("return "..ngx.unescape_uri(backend))()
local fm = 10000
nowindex = math.fmod(fm , table.getn(backendarr)) + 1
return backendarr[nowindex]? //nowindex簡(jiǎn)單隨機(jī)拿出其中一個(gè)后端ip
經(jīng)常使用nginx(tengine)的朋友可能注意到這里有兩個(gè)問題赘方;就是在后端發(fā)生異常情況的時(shí)候,后端節(jié)點(diǎn)的摘除和共享內(nèi)存的持久化問題弱左。
這個(gè)兩個(gè)問題點(diǎn)需要存在兩個(gè)東西窄陡,服務(wù)健康監(jiān)控系統(tǒng)和服務(wù)節(jié)點(diǎn)信息管理系統(tǒng)。
服務(wù)健康健康系統(tǒng):大家業(yè)務(wù)各有不同拆火,根據(jù)情況定造跳夭。
服務(wù)節(jié)點(diǎn)信息管理系統(tǒng):主要是維護(hù)服務(wù)注冊(cè)信息,我們現(xiàn)在lua 內(nèi)存共享變量是不另外做持久化處理们镜,只是在nginx(tengine)的重啟腳本里面加入調(diào)用服務(wù)節(jié)點(diǎn)信息系統(tǒng)步驟币叹,在nginx(tengine)重啟完后,進(jìn)行自動(dòng)調(diào)用服務(wù)節(jié)點(diǎn)信息管理系統(tǒng)獲取信息并寫入共享內(nèi)存中模狭。
總結(jié):經(jīng)過這樣改造颈抚,達(dá)到不需要reload restart nginx(tengine)情況下,進(jìn)行服務(wù)的擴(kuò)容和縮容嚼鹉。
-----------------------------------------
-----------------------------------------
以下內(nèi)容是摘自網(wǎng)上同行統(tǒng)計(jì)其它公司或開源模塊實(shí)現(xiàn)的動(dòng)態(tài)后端介紹:
1. nginx + upsync 模塊
這個(gè)方案在沙箱試了很久都沒有贩汉,功能上沒有任何問題驱富。但是在線上系統(tǒng)并發(fā)超過50k的情況下, reload nginx后幾分鐘會(huì)出現(xiàn)頁面無法訪問,靜態(tài)頁面的請(qǐng)求都變成下載了匹舞,最后導(dǎo)致整個(gè)應(yīng)用crash. 這個(gè)應(yīng)該是upsync的bug導(dǎo)致http response content type類型改變了褐鸥。沒有upsync開發(fā)者的幫助這個(gè)問題很難解決。
2. 右拍云的slardar
slardar 是基于nginx 1.9.5 然后集成了又拍云自己開發(fā)的一些lua module,還有春哥的balancer.lua 新模塊 并且結(jié)合consul k/v 實(shí)現(xiàn)了upstream動(dòng)態(tài)更新
slardar可以通過動(dòng)態(tài)更新consul的k/v存儲(chǔ)來添加upstream,添加lua script, 非常靈活赐稽。 不過這個(gè)需要對(duì)nginx的開發(fā)流程非常了解叫榕,并且熟悉nginx lua代碼
github上 https://github.com/upyun/slardar 目前還沒有人提issue和pr,估計(jì)只有又拍云自己在用了,目前來說通用性不好(雖然這個(gè)技術(shù)架構(gòu)和我們的架構(gòu)非常契合)
3. tengine + ngx_http_dyups_module
github 上 https://github.com/yzprofile/ngx_http_dyups_module 這個(gè)模塊已經(jīng)開源很久el并且merge到了tengine里姊舵,說明這個(gè)模塊已經(jīng)相當(dāng)成熟了, 這個(gè)模塊都是C編寫的效率肯定是超過用lua實(shí)現(xiàn)的
* ngx_http_dyups_module 提供了可以操作upstream的http restful api, 管理upstream變得非常容易
* 線上系統(tǒng)之前使用的nginx就是tengine, 所以使用這個(gè)方案會(huì)更容易一些晰绎,只需重新編譯并加一個(gè)dyups模塊,原來的配置無需改動(dòng)
* 現(xiàn)在線上系統(tǒng)的nginx是通過健康監(jiān)測(cè)模塊主動(dòng)check服務(wù)的端口號(hào)在不在蠢莺,這個(gè)檢測(cè)時(shí)有時(shí)間間隔的寒匙,線上的配置是
check interval=2000 rise=2 fall=3 timeout=1000;
這個(gè)健康監(jiān)測(cè)連續(xù)失敗3次nginx才會(huì)認(rèn)為后端實(shí)例不可用,即6s后躏将,nginx才會(huì)把一個(gè)有問題的實(shí)例屏蔽掉锄弱。通過consul service自己的健康監(jiān)測(cè)不需要這么長(zhǎng)的時(shí)間,幾乎是近實(shí)時(shí)的祸憋,dyups可以很快的拿掉有問題的實(shí)例会宪,影響小了很多。
4. consul nginx template
*consul template定義nginx配置文件模版蚯窥,從consul上讀取server信息(ip + port)掸鹅,然后更新nginx,并reload nginx. 這些都是consul幫助實(shí)現(xiàn)的,不過還是有reload操作拦赠。
更多文章巍沙,請(qǐng)關(guān)注微信訂閱號(hào):輕量運(yùn)維