為什么微服務(wù)一定要有API網(wǎng)關(guān)?

源?/??四猿外? ? ??文/?
微服務(wù)不能沒(méi)有網(wǎng)關(guān),就如同 Java 程序員不能沒(méi)有IDEA、Eclipse。為什么呢?
之所以網(wǎng)關(guān)對(duì)微服務(wù)這么重要,主要有以下幾點(diǎn)原因:
1. 解決 API 放哪里的問(wèn)題
要知道,采用微服務(wù)架構(gòu)的系統(tǒng)本身是由很多的獨(dú)立服務(wù)單元組合起來(lái)的。而客戶(hù)端要調(diào)用系統(tǒng),則必須通過(guò)系統(tǒng)提供的各種對(duì)外開(kāi)放的 API 來(lái)實(shí)現(xiàn)。
問(wèn)題來(lái)了,這些 API 要放在哪里呢?直接放在組成系統(tǒng)的服務(wù)單元上行不行?
比如,在一套電商系統(tǒng)上,關(guān)于訂單相關(guān)的 API ,放在組成訂單服務(wù)的服務(wù)單元上;風(fēng)控服務(wù)的 API ,放在組成風(fēng)控服務(wù)的服務(wù)單元上。

好,咱們假設(shè)有這么一個(gè)場(chǎng)景,有一位用戶(hù)想在這套電商系統(tǒng)上查看下商品詳情。那么,這個(gè)查看商品詳情的操作,就可能:
調(diào)用商品服務(wù)的 API 獲取商品描述 調(diào)用評(píng)價(jià)服務(wù)的 API 獲取相關(guān)評(píng)價(jià) 調(diào)用商家服務(wù)的 API 獲取商家信息 調(diào)用禮券服務(wù)的 API 獲取相關(guān)禮券 ……

可以看到,就這么一個(gè)商品查看操作,就可能會(huì)調(diào)用許多服務(wù)的 API。
那這些 API 如果全部分散到各個(gè)服務(wù)單元上,供客戶(hù)端調(diào)用,像查看商品這么簡(jiǎn)單的一次操作,客戶(hù)端就可能需要遠(yuǎn)程訪問(wèn)好幾次甚至十幾次服務(wù)器。
微服務(wù)自己又講究把 API 的粒度劃分的很細(xì),也就是說(shuō),可能從商品服務(wù)上調(diào)用商品信息,不止是調(diào)用一次商品服務(wù)就夠了,很可能需要多次對(duì)商品服務(wù)的不同 API 進(jìn)行調(diào)用,才能獲取到足夠的數(shù)據(jù)。
這樣一來(lái),客戶(hù)端需要訪問(wèn)服務(wù)器的次數(shù)就更多了,可能十幾次都不夠,得幾十次。
這種多次訪問(wèn)服務(wù)器的行為,會(huì)極大延遲客戶(hù)端的界面響應(yīng)時(shí)間,很不現(xiàn)實(shí)。
所以,把 API 放到各個(gè)業(yè)務(wù)相關(guān)的服務(wù)單元上,看上去問(wèn)題很大。
那為什么引入網(wǎng)關(guān)就能解決這個(gè)問(wèn)題呢?
因?yàn)橐刖W(wǎng)關(guān),就相當(dāng)于在客戶(hù)端和微服務(wù)之間加了一層隔離。通常,網(wǎng)關(guān)本身會(huì)和各個(gè)服務(wù)單元處于同一個(gè)機(jī)房,這樣,客戶(hù)端做業(yè)務(wù)操作的時(shí)候,只需要訪問(wèn)一次網(wǎng)關(guān)。然后剩下的事情,再由網(wǎng)關(guān)分別訪問(wèn)同在一個(gè)機(jī)房的不同的服務(wù),再把拿到的數(shù)據(jù)統(tǒng)一在網(wǎng)關(guān)封裝好,返回給客戶(hù)端就好。

2. 解決邊緣功能集成的問(wèn)題
在一套微服務(wù)組成的系統(tǒng)里,除了必須的業(yè)務(wù)功能以外,還有為了系統(tǒng)自身的健壯與安全,以及微服務(wù)本身的管理,而必須引入的一些非業(yè)務(wù)功能。對(duì)于這些非業(yè)務(wù)又很重要的功能,我們統(tǒng)稱(chēng)為邊緣功能。
還是拿電商系統(tǒng)為例,我們來(lái)看一些重要的邊緣功能。
假設(shè)因?yàn)槲覀冏隽艘淮畏浅4蟮拇黉N(xiāo)活動(dòng),導(dǎo)致流量過(guò)大,系統(tǒng)承載不了了。此時(shí),為了保證系統(tǒng)本身的穩(wěn)定,我們就需要把一些承載不了的流量給通過(guò)各種手段消化掉,一般的做法有三種:
限流:通過(guò)令牌桶等算法,把一些額外的流量擋在系統(tǒng)外面,不讓其訪問(wèn)。
降級(jí):由于系統(tǒng)可能已經(jīng)過(guò)載了,此時(shí),我們就放棄處理一些服務(wù)和頁(yè)面的請(qǐng)求或者僅簡(jiǎn)單處理,比如直接返回一個(gè)報(bào)錯(cuò)。
熔斷:有些時(shí)候,系統(tǒng)過(guò)載過(guò)度或者上線出了 bug,降級(jí)都解決不了問(wèn)題。比如,緩存失效了,導(dǎo)致大量請(qǐng)求頻繁訪問(wèn)了數(shù)據(jù)庫(kù),而這種頻繁訪問(wèn)數(shù)據(jù)庫(kù)可能造成了大量的 IO 操作,結(jié)果又去影響了數(shù)據(jù)庫(kù)所在的操作系統(tǒng),同時(shí),這個(gè)操作系統(tǒng)上又有著別的重要服務(wù),直接也被影響了。對(duì)于這種連鎖反應(yīng),我們稱(chēng)之為雪崩。而為了防止雪崩,我們就會(huì)堅(jiān)決把緩存失效導(dǎo)致數(shù)據(jù)庫(kù)被頻繁訪問(wèn)的服務(wù)給停掉,這就是熔斷。
可以看到,像限流、降級(jí)、熔斷這些系統(tǒng)保障策略,最合適的地方應(yīng)該是有一個(gè)集中的請(qǐng)求入口點(diǎn),就像古時(shí)候,老百姓進(jìn)城需要過(guò)城門(mén)那樣。
當(dāng)系統(tǒng)出現(xiàn)問(wèn)題的時(shí)候,直接就在這個(gè)入口點(diǎn)做相應(yīng)的操作即可。
限流,就直接在這個(gè)入口點(diǎn)限制后續(xù)請(qǐng)求。
降級(jí),就直接在這個(gè)入口點(diǎn)判斷請(qǐng)求想要訪問(wèn)的服務(wù)或者頁(yè)面,直接報(bào)錯(cuò)返回。
熔斷,就直接在這個(gè)入口點(diǎn),斷開(kāi)所有訪問(wèn)特定服務(wù)的請(qǐng)求連接,然后再把后繼對(duì)特定服務(wù)的訪問(wèn),也統(tǒng)統(tǒng)攔在門(mén)外。
在電商系統(tǒng)里,有很多特殊場(chǎng)景的接口,需要受到嚴(yán)格的限制。
比如,支付接口,訪問(wèn)它就需要認(rèn)證和權(quán)限控制。又比如,對(duì)于系統(tǒng)的訪問(wèn),有時(shí)候不能讓國(guó)外的去訪問(wèn)國(guó)內(nèi)的網(wǎng)站,這就需要限制客戶(hù)端的訪問(wèn) IP,所以系統(tǒng)還需要認(rèn)證和授權(quán)功能。
那這種認(rèn)證和授權(quán)也最合適放在請(qǐng)求的一個(gè)集中入口點(diǎn),統(tǒng)一實(shí)現(xiàn)。
還記得上面咱們說(shuō)過(guò)的網(wǎng)關(guān)的 API 統(tǒng)一存放嗎?我們只需要對(duì)這些 API 做對(duì)應(yīng)的權(quán)限設(shè)置,當(dāng)請(qǐng)求訪問(wèn)特殊場(chǎng)景接口的時(shí)候,必定會(huì)通過(guò) API 訪問(wèn)。所以,限制接口的訪問(wèn),本質(zhì)上就是對(duì)特定 API 的限制,那么,放在網(wǎng)關(guān)再合適不過(guò)了。
現(xiàn)實(shí)里,我們有時(shí)候需要把線上的流量鏡像出來(lái),轉(zhuǎn)發(fā)到灰度環(huán)境,利用這些鏡像出來(lái)的流量既可以用于小范圍測(cè)試,又可以更好的評(píng)估系統(tǒng)所能承載的最大吞吐量,也因此,系統(tǒng)需要有一個(gè)統(tǒng)一入口做分流。
可以看到,無(wú)論是系統(tǒng)需要的保障策略,認(rèn)證授權(quán),還是流量分流等功能,都應(yīng)該放到一個(gè)統(tǒng)一的請(qǐng)求入口處才能得到最好的實(shí)現(xiàn)。網(wǎng)關(guān)恰好就承擔(dān)了這么個(gè)統(tǒng)一請(qǐng)求入口的角色。
所以,對(duì)于微服務(wù)中,林林總總的邊緣功能,往往會(huì)通過(guò)插件的形式,集成在 API 網(wǎng)關(guān)中。
3. 解耦了客戶(hù)端和后端微服務(wù)
一套項(xiàng)目,在使用微服務(wù)模式的初期,往往后端變化是十分頻繁的。
頻繁變化的原因有很多,像業(yè)務(wù)領(lǐng)域劃分不合適啊,像某個(gè)業(yè)務(wù)模塊急速膨脹啊,都可能導(dǎo)致后端微服務(wù)的劇烈變化。
在這種情況下,如果沒(méi)有網(wǎng)關(guān),很可能就會(huì)出現(xiàn)客戶(hù)端需要被迫隨著后端的變化而變化的情況。
比如,在電商系統(tǒng)里,初期我們很可能會(huì)把風(fēng)控服務(wù)做的非常小。隨著業(yè)務(wù)的發(fā)展,風(fēng)控服務(wù)越來(lái)越龐大,此時(shí),風(fēng)控服務(wù)就可能被分解為決策引擎和分析中心等更多更細(xì)的服務(wù)。
在電商里,風(fēng)控往往是下單、支付等操作的必要前置操作。如果沒(méi)有網(wǎng)關(guān)去分隔開(kāi)客戶(hù)端和微服務(wù),客戶(hù)端直接和風(fēng)控服務(wù)打交道,那么風(fēng)控服務(wù)拆分,API 必然不會(huì)穩(wěn)定,API 的變化,自然會(huì)引發(fā)調(diào)用 API 客戶(hù)端代碼的變化。
有了網(wǎng)關(guān)之后,情況就好了很多了。當(dāng)風(fēng)控服務(wù)本身頻繁變化的時(shí)候,我們只需要改動(dòng)網(wǎng)關(guān)的代碼就好。而服務(wù)器代碼的升級(jí)可是遠(yuǎn)遠(yuǎn)要比客戶(hù)端代碼的升級(jí)容易太多了。
end

頂級(jí)程序員:topcoding
做最好的程序員社區(qū):Java后端開(kāi)發(fā)、Python、大數(shù)據(jù)、AI
一鍵三連「分享」、「點(diǎn)贊」和「在看」
