本文已經收錄自 JavaGuide (60k+ Star【Java學習+面試指南】 一份涵蓋大部分Java程序員所須要掌握的核心知識。)html
本文受權轉載自:github.com/javagrowing…。java
API網關能夠看作系統與外界聯通的入口,咱們能夠在網關進行處理一些非業務邏輯的邏輯,好比權限驗證,監控,緩存,請求路由等等。git
因爲在內部開發中咱們都是以RPC協議(thrift or dubbo)去作開發,暴露給內部服務,當外部服務須要使用這個接口的時候每每須要將RPC協議轉換成HTTP協議。程序員
在咱們的系統中因爲同一個接口新老兩套系統都在使用,咱們須要根據請求上下文將請求路由到對應的接口。github
對於鑑權操做不涉及到業務邏輯,那麼能夠在網關層進行處理,不用下層到業務邏輯。web
因爲網關是外部服務的入口,因此咱們能夠在這裏監控咱們想要的數據,好比入參出參,鏈路時間。面試
對於流量控制,熔斷降級非業務邏輯能夠統一放到網關層。redis
有不少業務都會本身去實現一層網關層,用來接入本身的服務,可是對於整個公司來講這還不夠。spring
統一的API網關不只有API網關的全部的特色,還有下面幾個好處:數據庫
在公司中若是有某個技術組件須要升級,那麼是須要和每一個業務線溝通,一般幾個月都搞不定。舉個例子若是對於入口的安全鑑權有重大安全隱患須要升級,若是速度仍是這麼慢確定是不行,那麼有了統一的網關升級是很快的。
對於某個服務的接入也比較困難,好比公司已經研發出了比較穩定的服務組件,正在公司大力推廣,這個週期確定也特別漫長,因爲有了統一網關,那麼只須要統一網關統一接入。
不一樣業務不一樣部門若是按照咱們上面的作法應該會都本身搞一個網關層,用來作這個事,能夠想象若是一個公司有100個這種業務,每一個業務配備4臺機器,那麼就須要400臺機器。而且每一個業務的開發RD都須要去開發這個網關層,去隨時去維護,增長人力。若是有了統一網關層,那麼也許只須要50臺機器就能夠作這100個業務的網關層的事,而且業務RD不須要隨時關注開發,上線的步驟。
對於咱們本身實現的網關層,因爲只有咱們本身使用,對於吞吐量的要求並不高因此,咱們通常同步請求調用便可。
對於咱們統一的網關層,如何用少許的機器接入更多的服務,這就須要咱們的異步,用來提升更多的吞吐量。對於異步化通常有下面兩種策略:
這種策略使用的比較廣泛,京東,有贊,Zuul,都選取的是這個策略,這種策略比較適合HTTP。在Servlet3中能夠開啓異步。
Netty爲高併發而生,目前惟品會的網關使用這個策略,在惟品會的技術文章中在相同的狀況下Netty是每秒30w+的吞吐量,Tomcat是13w+,能夠看出是有必定的差距的,可是Netty須要本身處理HTTP協議,這一塊比較麻煩。
對於網關是HTTP請求場景比較多的狀況能夠採用Servlet,畢竟有更加成熟的處理HTTP協議。若是更加劇視吞吐量那麼能夠採用Netty。
對於來的請求咱們已經使用異步了,爲了達到全鏈路異步因此咱們須要對去的請求也進行異步處理,對於去的請求咱們能夠利用咱們rpc的異步支持進行異步請求因此基本能夠達到下圖:
![img](https://user-gold-cdn.xitu.io/2019/11/7/16e45e6dcbf5d951?w=1300&h=480&f=png&s=31765)
由在web容器中開啓servlet異步,而後進入到網關的業務線程池中進行業務處理,而後進行rpc的異步調用並註冊須要回調的業務,最後在回調線程池中進行回調處理。
在設計模式中有一個模式叫責任鏈模式,他的做用是避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理它爲止。經過這種模式將請求的發送者和請求的處理者解耦了。在咱們的各個框架中對此模式都有實現,好比servlet裏面的filter,springmvc裏面的Interceptor。
在Netflix Zuul中也應用了這種模式,以下圖所示:
![img](https://user-gold-cdn.xitu.io/2019/11/7/16e45e6e386f7fa4?w=960&h=720&f=png&s=49314)
這種模式在網關的設計中咱們能夠借鑑到本身的網關設計:
這種設計在有讚的網關也有應用。
上面在全鏈路異步的狀況下不一樣業務之間的影響很小,可是若是在提供的自定義FiIlter中進行了某些同步調用,一旦超時頻繁那麼就會對其餘業務產生影響。因此咱們須要採用隔離之術,下降業務之間的互相影響。
信號量隔離只是限制了總的併發數,服務仍是主線程進行同步調用。這個隔離若是遠程調用超時依然會影響主線程,從而會影響其餘業務。所以,若是隻是想限制某個服務的總併發調用量或者調用的服務不涉及遠程調用的話,可使用輕量級的信號量來實現。有讚的網關因爲沒有自定義filter因此選取的是信號量隔離。
最簡單的就是不一樣業務之間經過不一樣的線程池進行隔離,就算業務接口出現了問題因爲線程池已經進行了隔離那麼也不會影響其餘業務。在京東的網關實現之中就是採用的線程池隔離,比較重要的業務好比商品或者訂單 都是單獨的經過線程池去處理。可是因爲是統一網關平臺,若是業務線衆多,你們都以爲本身的業務比較重要須要單獨的線程池隔離,若是使用的是Java語言開發的話那麼,在Java中線程是比較重的資源比較受限,若是須要隔離的線程池過多不是很適用。若是使用一些其餘語言好比Golang進行開發網關的話,線程是比較輕的資源,因此比較適合使用線程池隔離。
若是有某些業務就須要使用隔離可是統一網關又沒有線程池隔離那麼應該怎麼辦呢?那麼可使用集羣隔離,若是你的某些業務真的很重要那麼能夠爲這一系列業務單獨申請一個集羣或者多個集羣,經過機器之間進行隔離。
流量控制能夠採用不少開源的實現,好比阿里最近開源的Sentinel和比較成熟的Hystrix。
通常限流分爲集羣限流和單機限流:
這一塊也能夠參照開源的實現Sentinel和Hystrix,這裏不是重點就很少提了。
泛化調用指的是一些通訊協議的轉換,好比將HTTP轉換成Thrift。在一些開源的網關中好比Zuul是沒有實現的,由於各個公司的內部服務通訊協議都不一樣。好比在惟品會中支持HTTP1,HTTP2,以及二進制的協議,而後轉化成內部的協議,淘寶的支持HTTPS,HTTP1,HTTP2這些協議均可以轉換成,HTTP,HSF,Dubbo等協議。
如何去實現泛化調用呢?因爲協議很難自動轉換,那麼其實每一個協議對應的接口須要提供一種映射。簡單來講就是把兩個協議都能轉換成共同語言,從而互相轉換。
![img](https://user-gold-cdn.xitu.io/2019/11/7/16e45e6ef627076e?w=1338&h=963&f=png&s=80170)通常來講共同語言有三種方式指定:
好比能夠將一個 www.baidu.com/id = 1 GET 能夠映射爲json:
代碼塊
複製代碼
對於泛化調用若是要本身設計的話JSON基本能夠知足,若是對於個性化的須要特別多的話卻是能夠本身定義一套語言。
上面介紹的都是如何實現一個網關的技術關鍵。這裏須要介紹網關的一個業務關鍵。有了網關以後,須要一個管理平臺如何去對咱們上面所描述的技術關鍵進行配置,包括但不限於下面這些配置:
最後一個合理的標準網關應該按照以下去實現:
![img](https://user-gold-cdn.xitu.io/2019/11/7/16e45e6fb4b82f73?w=2013&h=1007&f=png&s=152690)
--- |
京東 |
惟品會 |
有贊 |
阿里 |
Zuul |
---|---|---|---|---|---|
實現關鍵 | servlet3.0 |
netty |
servlet3.0 |
servlet3.0 |
servlet3.0 |
異步狀況 | servlet異步,rpc是否異步不清楚 | 全鏈路異步 |
全鏈路異步 |
全鏈路異步 |
Zuul1同步阻塞,Zuul2異步非阻塞 |
限流 |
--- |
--- |
平滑限流。最初是codis,後續換到每一個單機的令牌桶限流。 | 1.基本流控:基於API的QPS作限流。2.運營流控:支持APP流量包,APP+API+USER的流控33.大促流控:APP訪問API的權重流控。阿里開源:Sentinel | 提供了jar包:spring-cloud-zuul-ratelimit。1.對請求的目標URL進行限流(例如:某個URL每分鐘只容許調用多少次)。2.對客戶端的訪問IP進行限流(例如:某個IP每分鐘只容許請求多少次)3.對某些特定用戶或者用戶組進行限流(例如:非VIP用戶限制每分鐘只容許調用100次某個API等)4.多維度混合的限流。此時,就須要實現一些限流規則的編排機制。與、或、非等關係。支持四種存儲方式ConcurrentHashMap,Consul,Redis,數據庫。 |
熔斷降級 | --- |
--- |
Hystrix |
--- |
只支持服務級別熔斷,不支持URL級別。 |
隔離 |
線程池隔離 |
--- |
信號量隔離 |
--- |
線程池隔離,信號量隔離 |
緩存 |
redis |
--- |
二級緩存,本地緩存+Codis |
HDCC 本地緩存,遠程緩存,數據庫 |
須要本身開發 |
泛化調用 | --- |
http,https,http1,http2,二進制 | dubbo,http,nova |
hsf,dubbo,http,https,http2,http1 |
只支持http |
做者的其餘開源項目推薦: