API 網(wǎng)關(guān)入門到放棄
用途
鑒權(quán)
限流
權(quán)限
熔斷
協(xié)議轉(zhuǎn)換
內(nèi)部的API可能是由很多種不同的協(xié)議實(shí)現(xiàn)的,比如HTTP、Dubbo、GRPC等,但對(duì)于用戶來說其中很多都不是很友好,或者根本沒法對(duì)外暴露,比如Dubbo服務(wù),因此需要在網(wǎng)關(guān)層做一次協(xié)議轉(zhuǎn)換,將用戶的HTTP協(xié)議請(qǐng)求,在網(wǎng)關(guān)層轉(zhuǎn)換成底層對(duì)應(yīng)的協(xié)議,比如HTTP -> Dubbo, 但這里需要注意很多問題,比如參數(shù)類型,如果類型搞錯(cuò)了,導(dǎo)致轉(zhuǎn)換出問題,而日志又不夠詳細(xì)的話,問題會(huì)很難定位
接入
第一種采用插件掃描業(yè)務(wù)方的API,比如spring mvc的注解, 并結(jié)合swagger的注解, 從而實(shí)現(xiàn)參數(shù)校驗(yàn), 文檔&&SDK生成等功能, 掃描完成之后,需要上報(bào)到網(wǎng)管的存儲(chǔ)服務(wù)
手動(dòng)錄入, …….
配置文件導(dǎo)入, 比如通過swagger\openAPI等, 比如阿里云的網(wǎng)關(guān)
服務(wù)發(fā)現(xiàn)
網(wǎng)關(guān)作為流量的入口, 負(fù)責(zé)請(qǐng)求的轉(zhuǎn)發(fā), 但首先需要知道轉(zhuǎn)發(fā)給誰, 如何尋址
寫死在代碼或配置文件中
域名
注冊(cè)中心
服務(wù)調(diào)用
網(wǎng)關(guān)由于對(duì)接很多種不同的協(xié)議,因此可能需要實(shí)現(xiàn)很多種調(diào)用方式,比如HTTP、Dubbo等,基于性能原因,最好都采用異步的方式,而Http、Dubbo都是支持異步的,比如apache就提供了基于NIO實(shí)現(xiàn)的異步HTTP客戶端。
因?yàn)榫W(wǎng)關(guān)會(huì)涉及到很多異步調(diào)用,比如攔截器、HTTP客戶端、dubbo、redis等,因此需要考慮下異步調(diào)用的方式,如果基于回調(diào)或者future的話,代碼嵌套會(huì)很深,可讀性很差,可以參考zuul和spring cloud gateway的方案,基于響應(yīng)式進(jìn)行改造。
優(yōu)雅下線
優(yōu)雅下線也是網(wǎng)關(guān)需要關(guān)注的一個(gè)問題,網(wǎng)關(guān)底層會(huì)涉及到很多種協(xié)議,比如HTTP、Dubbo,而HTTP又可以繼續(xù)細(xì)分,比如域名、注冊(cè)中心等,有些自身就支持優(yōu)雅下線,比如Nginx自身是支持健康監(jiān)測(cè)機(jī)制的,如果檢測(cè)到某一個(gè)節(jié)點(diǎn)已經(jīng)掛掉了,就會(huì)把這個(gè)節(jié)點(diǎn)摘掉,對(duì)于應(yīng)用正常下線,需要結(jié)合發(fā)布系統(tǒng),首先進(jìn)行邏輯下線,然后對(duì)后續(xù)Nginx的健康監(jiān)測(cè)請(qǐng)求直接返回失敗(比如直接返回500),然后等待一段時(shí)間(根據(jù)Nginx配置決定),然后再將應(yīng)用實(shí)際下線掉。另外對(duì)于注冊(cè)中心的其實(shí)也類似,一般注冊(cè)中心是只支持手動(dòng)下線的,可以在邏輯下線階段調(diào)用注冊(cè)中心的接口將節(jié)點(diǎn)下線掉,而有些不支持主動(dòng)下線的,需要結(jié)合緩存的配置,讓應(yīng)用延遲下線。另外對(duì)于其他比如Dubbo等原理也是類似。
性能
網(wǎng)關(guān)作為所有流量的入口,性能是重中之重,早期大部分網(wǎng)關(guān)都是基于同步阻塞模型構(gòu)建的,比如Zuul 1.x。但這種同步的模型我們都知道,每個(gè)請(qǐng)求/連接都會(huì)占用一個(gè)線程,而線程在JVM中是一個(gè)很重的資源,比如Tomcat默認(rèn)就是200個(gè)線程,如果網(wǎng)關(guān)隔離沒有做好的話,當(dāng)發(fā)生網(wǎng)絡(luò)延遲、FullGC、第三方服務(wù)慢等情況造成上游服務(wù)延遲時(shí),線程池很容易會(huì)被打滿,造成新的請(qǐng)求被拒絕,但這個(gè)時(shí)候其實(shí)線程都阻塞在IO上,系統(tǒng)的資源被沒有得到充分的利用。另外一點(diǎn),容易受網(wǎng)絡(luò)、磁盤IO等延遲影響。需要謹(jǐn)慎設(shè)置超時(shí)時(shí)間,如果設(shè)置不當(dāng),且服務(wù)隔離做的不是很完善的話,網(wǎng)關(guān)很容易被一個(gè)慢接口拖垮。
而異步化的方式則完全不同,通常情況下一個(gè)CPU核啟動(dòng)一個(gè)線程即可處理所有的請(qǐng)求、響應(yīng)。一個(gè)請(qǐng)求的生命周期不再固定于一個(gè)線程,而是會(huì)分成不同的階段交由不同的線程池處理,系統(tǒng)的資源能夠得到更充分的利用。而且因?yàn)榫€程不再被某一個(gè)連接獨(dú)占,一個(gè)連接所占用的系統(tǒng)資源也會(huì)低得多,只是一個(gè)文件描述符加上幾個(gè)監(jiān)聽器等,而在阻塞模型中,每條連接都會(huì)獨(dú)占一個(gè)線程,而線程是一個(gè)非常重的資源。對(duì)于上游服務(wù)的延遲情況,也能夠得到很大的緩解,因?yàn)樵谧枞P椭校?qǐng)求會(huì)獨(dú)占一個(gè)線程資源,而異步化之后,因?yàn)閱螚l連接所占用的資源變的非常低,系統(tǒng)可以同時(shí)處理大量的請(qǐng)求。
如果是JVM平臺(tái),Zuul 2、Spring Cloud gateway等都是不錯(cuò)的異步網(wǎng)關(guān)選型,另外也可以基于Netty、Spring Boot2.x的webflux、vert.x或者servlet3.1的異步支持進(jìn)行自研。
緩存
對(duì)于一些冪等的get請(qǐng)求,可以在網(wǎng)關(guān)層面根據(jù)業(yè)務(wù)方指定的緩存頭做一層緩存,存儲(chǔ)到Redis等二級(jí)緩存中,這樣一些重復(fù)的請(qǐng)求,可以在網(wǎng)關(guān)層直接處理,而不用打到業(yè)務(wù)線,降低業(yè)務(wù)方的壓力,另外如果業(yè)務(wù)方節(jié)點(diǎn)掛掉,網(wǎng)關(guān)也能夠返回自身的緩存。
限流
限流對(duì)于每個(gè)業(yè)務(wù)組件來說,可以說都是一個(gè)必須的組件,如果限流做不好的話,當(dāng)請(qǐng)求量突增時(shí),很容易導(dǎo)致業(yè)務(wù)方的服務(wù)掛掉,比如雙11、雙12等大促時(shí),接口的請(qǐng)求量是平時(shí)的數(shù)倍,如果沒有評(píng)估好容量,又沒有做限流的話,很容易服務(wù)整個(gè)不可用,因此需要根據(jù)業(yè)務(wù)方接口的處理能力,做好限流策略,相信大家都見過淘寶、百度搶紅包時(shí)的降級(jí)頁面。
因此一定要在接入層做好限流策略,對(duì)于非核心接口可以直接將降級(jí)掉,保障核心服務(wù)的可用性,對(duì)于核心接口,需要根據(jù)壓測(cè)時(shí)得到的接口容量,制定對(duì)應(yīng)的限流策略。限流又分為幾種:
單機(jī)。單機(jī)性能比較高,不涉及遠(yuǎn)程調(diào)用,只是本地計(jì)數(shù),對(duì)接口RT影響最小。但需要考慮下限流數(shù)的設(shè)置,比如是針對(duì)單臺(tái)網(wǎng)關(guān)、還是整個(gè)網(wǎng)關(guān)集群,如果是整個(gè)集群的話,需要考慮到網(wǎng)關(guān)縮容、擴(kuò)容時(shí)修改對(duì)應(yīng)的限流數(shù)。
分布式。分布式的就需要一個(gè)存儲(chǔ)節(jié)點(diǎn)維護(hù)當(dāng)前接口的調(diào)用數(shù),比如redis、sentinel等,這種方式由于涉及到遠(yuǎn)程調(diào)用,會(huì)有些性能損耗,另外也需要考慮到存儲(chǔ)掛掉的問題,比如redis如果掛掉,網(wǎng)關(guān)需要考慮降級(jí)方案,是降級(jí)到本地限流,還是直接將限流功能本身降級(jí)掉。
另外還有不同的策略:簡(jiǎn)單計(jì)數(shù)、令牌桶等,大部分場(chǎng)景下其實(shí)簡(jiǎn)單計(jì)數(shù)已經(jīng)夠用了,但如果需要支持突發(fā)流量等場(chǎng)景時(shí),可以采用令牌桶等方案。還需要考慮根據(jù)什么限流,比如是IP、接口、用戶維度、還是請(qǐng)求參數(shù)中的某些值,這里可以采用表達(dá)式,相對(duì)比較靈活。
穩(wěn)定性
穩(wěn)定性是網(wǎng)關(guān)非常重要的一環(huán),監(jiān)控、告警需要做的很完善才可以,比如接口調(diào)用量、響應(yīng)時(shí)間、異常、錯(cuò)誤碼、成功率等相關(guān)的監(jiān)控告警,還有線程池相關(guān)的一些,比如活躍線程數(shù)、隊(duì)列積壓等,還有些系統(tǒng)層面的,比如CPU、內(nèi)存、FullGC這些基本的。
網(wǎng)關(guān)是所有服務(wù)的入口,對(duì)于網(wǎng)關(guān)的穩(wěn)定性的要求相對(duì)于其他服務(wù)會(huì)更高,最好能夠一直穩(wěn)定的運(yùn)行,盡量少重啟,但當(dāng)新增功能、或者加日志排查問題時(shí),不可避免的需要重新發(fā)布,因此可以參考zuul的方式,將所有的核心功能都基于不同的攔截器實(shí)現(xiàn),攔截器的代碼采用Groovy編寫,存儲(chǔ)到數(shù)據(jù)庫中,支持動(dòng)態(tài)加載、編譯、運(yùn)行,這樣在出了問題的時(shí)候能夠第一時(shí)間定位并解決,并且如果網(wǎng)關(guān)需要開發(fā)新功能,只需要增加新的攔截器,并動(dòng)態(tài)添加到網(wǎng)關(guān)即可,不需要重新發(fā)布。
熔斷降級(jí)
熔斷機(jī)制也是非常重要的一項(xiàng)。若某一個(gè)服務(wù)掛掉、接口響應(yīng)嚴(yán)重超時(shí)等發(fā)生,則可能整個(gè)網(wǎng)關(guān)都被一個(gè)接口拖垮,因此需要增加熔斷降級(jí),當(dāng)發(fā)生特定異常的時(shí)候,對(duì)接口降級(jí)由網(wǎng)關(guān)直接返回,可以基于Hystrix或者Resilience4j實(shí)現(xiàn)。
日志
由于所有的請(qǐng)求都是由網(wǎng)關(guān)處理的,因此日志也需要相對(duì)比較完善,比如接口的耗時(shí)、請(qǐng)求方式、請(qǐng)求IP、請(qǐng)求參數(shù)、響應(yīng)參數(shù)(注意脫敏)等,另外由于可能涉及到很多微服務(wù),因此需要提供一個(gè)統(tǒng)一的traceId方便關(guān)聯(lián)所有的日志,可以將這個(gè)traceId置于響應(yīng)頭中,方便排查問題。
隔離
比如線程池、http連接池、redis等應(yīng)用層面的隔離,另外也可以根據(jù)業(yè)務(wù)場(chǎng)景,將核心業(yè)務(wù)部署帶單獨(dú)的網(wǎng)關(guān)集群,與其他非核心業(yè)務(wù)隔離開。
網(wǎng)關(guān)管控平臺(tái)
這塊也是非常重要的一環(huán),需要考慮好整個(gè)流程的用戶體驗(yàn),比如接入到網(wǎng)關(guān)的這個(gè)流程,能不能盡量簡(jiǎn)化、智能,比如如果是dubbo接口,我們可以通過到git倉庫中獲取源碼、解析對(duì)應(yīng)的類、方法,從而實(shí)現(xiàn)自動(dòng)填充,盡量幫用戶減少操作;另外接口一般是從測(cè)試->預(yù)發(fā)->線上,如果每次都要填寫一遍表單會(huì)非常麻煩,我們能不能自動(dòng)把這個(gè)事情做掉,另外如果網(wǎng)關(guān)部署到了多個(gè)可用區(qū)、甚至不同的國家,那這個(gè)時(shí)候,我們還需要接口數(shù)據(jù)同步功能,不然用戶需要到每個(gè)后臺(tái)都操作一遍,非常麻煩。
這塊個(gè)人的建議是直接參考阿里云、aws等提供的網(wǎng)關(guān)服務(wù)即可,功能非常全面。
其他
其他還有些需要考慮到的點(diǎn),比如接口mock,文檔生成、sdk代碼生成、錯(cuò)誤碼統(tǒng)一、服務(wù)治理相關(guān)的等
總結(jié)
目前的網(wǎng)關(guān)還是中心化的架構(gòu),所有的請(qǐng)求都需要走一次網(wǎng)關(guān),因此當(dāng)大促或者流量突增時(shí),網(wǎng)關(guān)可能會(huì)成為性能的瓶頸,而且當(dāng)網(wǎng)關(guān)接入的大量接口的時(shí)候,做好流量評(píng)估也不是一項(xiàng)容易的工作,每次大促前都需要跟業(yè)務(wù)方一起針對(duì)接口做壓測(cè),評(píng)估出大致的容量,并對(duì)網(wǎng)關(guān)進(jìn)行擴(kuò)容,而且網(wǎng)關(guān)是所有流量的入口,所有的請(qǐng)求都是由網(wǎng)關(guān)處理,要想準(zhǔn)確的評(píng)估出容量很復(fù)雜。可以參考目前比較流行的ServiceMesh,采用去中心化的方案,將網(wǎng)關(guān)的邏輯下沉到sidecar中,sidecar和應(yīng)用部署到同一個(gè)節(jié)點(diǎn),并接管應(yīng)用流入、流出的流量,這樣大促時(shí),只需要對(duì)相關(guān)的業(yè)務(wù)壓測(cè),并針對(duì)性擴(kuò)容即可,另外升級(jí)也會(huì)更平滑,中心化的網(wǎng)關(guān),即使灰度發(fā)布,但是理論上所有業(yè)務(wù)方的流量都會(huì)流入到新版本的網(wǎng)關(guān),如果出了問題,會(huì)影響到所有的業(yè)務(wù),但這種去中心化的方式,可以先針對(duì)非核心業(yè)務(wù)升級(jí),觀察一段時(shí)間沒問題后,再全量推上線。另外ServiceMesh的方案,對(duì)于多語言支持也更友好
來源:https://www.yuque.com/huanmeng-ftsgv/shang/lpfdlr#WP8MM
推薦閱讀
一文搞懂什么是 vlan、三層交換機(jī)、網(wǎng)關(guān)、DNS、子網(wǎng)掩碼、MAC地址
100 個(gè)網(wǎng)絡(luò)基礎(chǔ)知識(shí)普及,看完成半個(gè)網(wǎng)絡(luò)高手!
小白也能看懂的網(wǎng)絡(luò)基礎(chǔ) | 01 什么是網(wǎng)絡(luò)?
請(qǐng)收好這一份詳細(xì) & 清晰的計(jì)算機(jī)網(wǎng)絡(luò)基礎(chǔ)學(xué)習(xí)指南!

