PaaS 7層動(dòng)態(tài)路由的若干實(shí)現(xiàn)
隨著Docker的出現(xiàn),PaaS、CaaS(Container As A Service)、甚至DCOS(DataCenter OS)呈現(xiàn)了爆發(fā)式的發(fā)展。而在PaaS中,因?yàn)閷?shí)例一般默認(rèn)為動(dòng)態(tài)IP,對(duì)于7層調(diào)用(比如http請(qǐng)求),需要7層動(dòng)態(tài)路由獲取應(yīng)用域名(或虛IP)和后端實(shí)例的映射關(guān)系,以提供7層服務(wù);而對(duì)于4層調(diào)用(比如rpc調(diào)用),可以通過(guò)動(dòng)態(tài)LVS或名字服務(wù)(或基于zookeeper/etcd等實(shí)現(xiàn)的服務(wù)注冊(cè)和發(fā)現(xiàn)工具)進(jìn)行調(diào)用。
簡(jiǎn)單舉例,開(kāi)發(fā)者在PaaS里創(chuàng)建了一個(gè)APP,包含若干個(gè)實(shí)例,然后為APP綁定某個(gè)域名。用戶對(duì)APP發(fā)出請(qǐng)求,需要經(jīng)過(guò)后端實(shí)例的處理才能正確的返回。那么作為7層動(dòng)態(tài)路由,核心就是獲取域名(或虛IP)與后端實(shí)例的對(duì)應(yīng)關(guān)系并作為反向代理完成請(qǐng)求轉(zhuǎn)發(fā)。
這里簡(jiǎn)單討論下7層動(dòng)態(tài)路由的若干實(shí)現(xiàn)。因?yàn)閚ginx是一個(gè)高性能的反向代理服務(wù)器,以是否基于nginx實(shí)現(xiàn)7層動(dòng)態(tài)路由,可以將這些實(shí)現(xiàn)大概分為兩大類。
***類,不依賴nginx,項(xiàng)目自身實(shí)現(xiàn)了反向代理的功能。
CloudFoundry可以說(shuō)是***代的開(kāi)源PaaS項(xiàng)目,其模塊gorouter即為一個(gè)動(dòng)態(tài)路由實(shí)現(xiàn)(同時(shí)支持4層和7層)。以 CloudFoundry (release v164)為例,使用nats作為消息總線,對(duì)各模塊調(diào)用和消息傳遞進(jìn)行解耦??梢钥聪耮orouter (tag 45ca951297)的代碼,registry/registry.go里實(shí)現(xiàn)了相應(yīng)邏輯代碼,以獲取域名和后端實(shí)例的對(duì)應(yīng)關(guān)系。其大概流程為:
實(shí)例啟動(dòng)后向nats發(fā)布消息,gorouter則會(huì)訂閱這些消息,從而獲取應(yīng)用域名和后端實(shí)例的對(duì)應(yīng)關(guān)系;同時(shí)gorouter使用goroutine實(shí)現(xiàn)了高性能的請(qǐng)求處理和轉(zhuǎn)發(fā),支持4層和7層調(diào)用。
Docker出現(xiàn)后,基于Docker的輕量級(jí)PaaS紛紛涌現(xiàn),大家可能會(huì)把實(shí)例信息(如IP信息等)存儲(chǔ)在redis(或其它數(shù)據(jù)存儲(chǔ))。開(kāi)源項(xiàng)目DINP基本就是這樣的實(shí)現(xiàn),dinp-router fork自CloudFoundry的gorouter (tag 45ca951297),更改了部分代碼,以獲取應(yīng)用域名和redis中存儲(chǔ)的后端實(shí)例的對(duì)應(yīng)關(guān)系,從而實(shí)現(xiàn)了7層動(dòng)態(tài)路由的功能。
類似的,dotCloud的hipache則是利用nodejs的http庫(kù)實(shí)現(xiàn)了請(qǐng)求轉(zhuǎn)發(fā),后端實(shí)例信息則可以存儲(chǔ)在redis中。
當(dāng)然,很多工程師在7層的選型上還是更信賴nginx,畢竟nginx在性能、穩(wěn)定性、擴(kuò)展性上都是不二之選。基于nginx來(lái)實(shí)現(xiàn)7層動(dòng)態(tài)路由,大概又有兩種實(shí)現(xiàn)思路。
其一,基于名字服務(wù)(或基于zookeeper/etcd等實(shí)現(xiàn)的服務(wù)注冊(cè)和發(fā)現(xiàn)工具),通過(guò)watch或定時(shí)調(diào)度,將注冊(cè)的后端實(shí)例更新到 nginx配置文件的upstream中,從而實(shí)現(xiàn)后端的(準(zhǔn))實(shí)時(shí)變化。這方面也有如confd等的開(kāi)源工具。confd基于golang的 template庫(kù),將nginx配置文件作為模板;支持consul/etcd/redis/zookeeper等諸多后端存儲(chǔ),通過(guò)watch或定時(shí)調(diào)度從這些后端獲取實(shí)例信息,并更新到nginx配置文件模板,從而實(shí)現(xiàn)(準(zhǔn))實(shí)時(shí)的7層動(dòng)態(tài)路由。這種實(shí)現(xiàn)邏輯簡(jiǎn)單,穩(wěn)定性高,但在大規(guī)模應(yīng)用時(shí) nginx可能會(huì)較頻繁的reload。
其二,基于nginx-lua實(shí)現(xiàn)。每次用戶請(qǐng)求到達(dá)相應(yīng)upstream時(shí),通過(guò)nginx-lua從redis等數(shù)據(jù)存儲(chǔ)中獲得后端實(shí)例信息,從而實(shí)現(xiàn)請(qǐng)求的轉(zhuǎn)發(fā)。nginx獲取redis數(shù)據(jù)需要進(jìn)行一次網(wǎng)絡(luò)請(qǐng)求,同機(jī)房的時(shí)延一般是毫秒級(jí),但在大訪問(wèn)量時(shí)可能存在一定問(wèn)題,因此可以使用 lua-shared-dict作為系統(tǒng)緩存。
參考:
https://github.com/openresty/lua-nginx-module
http://segmentfault.com/a/1190000004128807?luicode=10000359&luicode=10000359