使用網(wǎng)關(guān)可以將多個(gè)單獨(dú)的請(qǐng)求聚合到一個(gè)請(qǐng)求中。當(dāng)客戶端必須對(duì)多個(gè)不同的后端系統(tǒng)進(jìn)行多次調(diào)用操作時(shí),此模式很有用。
背景及問題
有時(shí)候執(zhí)行單個(gè)任務(wù)時(shí),客戶端可能必須對(duì)不同的各個(gè)后端服務(wù)進(jìn)行多次調(diào)用。因?yàn)樗麄円蕾囉诙鄠€(gè)服務(wù),那么客戶端必須調(diào)用不同的服務(wù)接口以完成這次請(qǐng)求,這樣就會(huì)導(dǎo)致請(qǐng)求過多而浪費(fèi)很多的資源。當(dāng)任何新功能或服務(wù)添加到應(yīng)用程序時(shí),從而會(huì)進(jìn)一步增加資源需求和網(wǎng)絡(luò)調(diào)用。客戶端和后端之間的這種混亂調(diào)用可能會(huì)對(duì)應(yīng)用程序的性能和規(guī)模產(chǎn)生負(fù)面影響。微服務(wù)架構(gòu)使這個(gè)問題變得更加普遍,因?yàn)閲@許多小型服務(wù)構(gòu)建的應(yīng)用程序自然會(huì)有更多的跨服務(wù)調(diào)用。
在下圖中,客戶端向每個(gè)服務(wù)發(fā)送請(qǐng)求(1,2,3)。每個(gè)服務(wù)處理請(qǐng)求并將響應(yīng)發(fā)送回應(yīng)用程序(4,5,6)。通常具有高延遲的蜂窩網(wǎng)絡(luò)上,以這種方式使用單獨(dú)的請(qǐng)求是低效的并且可能導(dǎo)致連接中斷或請(qǐng)求不完整。雖然每個(gè)請(qǐng)求可以并行完成,但應(yīng)用程序必須為每個(gè)請(qǐng)求發(fā)送,等待和處理數(shù)據(jù),所有這些都在不同的連接上,從而增加了失敗的可能性。

解決方案:
使用網(wǎng)關(guān)來(lái)減少客戶端和服務(wù)之間的干擾。網(wǎng)關(guān)接收客戶端請(qǐng)求,將請(qǐng)求分派給各種后端系統(tǒng),然后聚合結(jié)果并將它們發(fā)送回請(qǐng)求客戶端。
這種模式可以有效減少應(yīng)用程序?qū)蠖朔?wù)的調(diào)用請(qǐng)求數(shù),而且在高延遲網(wǎng)絡(luò)上的應(yīng)用程序的性能有大的提升。
在下圖中,應(yīng)用程序向網(wǎng)關(guān)發(fā)送請(qǐng)求(1)。該請(qǐng)求包含一組附加請(qǐng)求。網(wǎng)關(guān)分解這些請(qǐng)求并通過將每個(gè)請(qǐng)求發(fā)送到相關(guān)服務(wù)來(lái)處理每個(gè)請(qǐng)求(2)。每個(gè)服務(wù)都返回對(duì)網(wǎng)關(guān)的響應(yīng)(3)。網(wǎng)關(guān)聚合每個(gè)服務(wù)的響應(yīng)并將響應(yīng)發(fā)送到應(yīng)用程序(4)。應(yīng)用程序發(fā)出單個(gè)請(qǐng)求,并且只從網(wǎng)關(guān)接收一個(gè)響應(yīng)。

問題和思考
1.網(wǎng)關(guān)不應(yīng)該在后端服務(wù)中引入服務(wù)耦合
2.網(wǎng)關(guān)應(yīng)該和后端服務(wù)位置很近,以盡可能減少延遲。
3.網(wǎng)關(guān)服務(wù)可能須要做ha。確保網(wǎng)關(guān)設(shè)計(jì)合理,以滿足您的應(yīng)用程序的可用性要求。
4.網(wǎng)關(guān)可能是性能瓶頸。確保網(wǎng)關(guān)具有足夠的性能來(lái)處理負(fù)載,并且可以擴(kuò)展以滿足您的預(yù)期增長(zhǎng)。
5.對(duì)網(wǎng)關(guān)執(zhí)行負(fù)載測(cè)試,以確保不會(huì)導(dǎo)致服務(wù)的級(jí)聯(lián)故障。
6.使用隔板,斷路,重試和超時(shí)等技術(shù)實(shí)現(xiàn)彈性設(shè)計(jì)。
7.如果一個(gè)或多個(gè)服務(wù)調(diào)用花費(fèi)的時(shí)間太長(zhǎng),則可以接受超時(shí)并返回部分?jǐn)?shù)據(jù)集。考慮您的應(yīng)用程序?qū)⑷绾翁幚泶朔桨浮?br>
8.使用異步I / O來(lái)提升程序的吞吐量。
9.通過分布式跟蹤對(duì)全鏈路進(jìn)行監(jiān)控。
10.監(jiān)控請(qǐng)求指標(biāo)和響應(yīng)大小。
11.考慮將緩存數(shù)據(jù)作為故障轉(zhuǎn)移策略來(lái)處理故障。
12.不要將聚合構(gòu)建到網(wǎng)關(guān)中,而是考慮在網(wǎng)關(guān)后面放置聚合服務(wù)。請(qǐng)求聚合可能具有與網(wǎng)關(guān)中的其他服務(wù)不同的資源要求,并且可能影響網(wǎng)關(guān)的路由和卸載功能。
什么時(shí)候使用該模式
適用的場(chǎng)景:
1.客戶端需要與多個(gè)后端服務(wù)通信才能完成操作
2.客戶端可以使用具有明顯延遲的網(wǎng)絡(luò),例如蜂窩網(wǎng)絡(luò)。
不適用的場(chǎng)景:
1.您希望客戶端對(duì)單個(gè)服務(wù)的請(qǐng)求次數(shù)(比如獲取10個(gè)學(xué)生的信息,你只有一個(gè)單個(gè)查詢學(xué)生信息的接口)。在這種情況下,最好向服務(wù)添加批處理操作。
2.客戶端或應(yīng)用程序位于后端服務(wù)附近,延遲不是一個(gè)重要因素。
例子
以下示例是教你如何使用Lua創(chuàng)建簡(jiǎn)單的網(wǎng)關(guān)聚合NGINX服務(wù)。
worker_processes 4;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location = /batch {
content_by_lua '
ngx.req.read_body()
-- read json body content
local cjson = require "cjson"
local batch = cjson.decode(ngx.req.get_body_data())["batch"]
-- create capture_multi table
local requests = {}
for i, item in ipairs(batch) do
table.insert(requests, {item.relative_url, { method = ngx.HTTP_GET}})
end
-- execute batch requests in parallel
local results = {}
local resps = { ngx.location.capture_multi(requests) }
for i, res in ipairs(resps) do
table.insert(results, {status = res.status, body = cjson.decode(res.body), header = res.header})
end
ngx.say(cjson.encode({results = results}))
';
}
location = /service1 {
default_type application/json;
echo '{"attr1":"val1"}';
}
location = /service2 {
default_type application/json;
echo '{"attr2":"val2"}';
}
}
}