本文準備圍繞七個點來說網關,分別是網關的基本概念、網關設計思路、網關設計重點、流量網關、業務網關、常見網關對比,對基礎概念熟悉的朋友能夠根據目錄查看本身感興趣的部分。html
網關,不少地方將網關好比成門, 沒什麼問題, 可是須要區分網關與網橋的區別,前端
網橋工做在數據鏈路層,在不一樣或相同類型的LAN之間存儲並轉發數據幀,必要時進行鏈路層上的協議轉換。可鏈接兩個或多個網絡,在其中傳送信息包。nginx
網關是一個大概念,不具體特指一類產品,只要鏈接兩個不一樣的網絡均可以叫網關,網橋通常只轉發信息,而網關可能進行包裝。git
根據網關的特性,舉個例子:github
假如你要去找集團老闆(這兒只是舉個例子), 你們都知道老闆確定不是誰想見就能見的, 也怕壞人嘛, 那麼你去老闆所在的辦公樓,假如是集團總部, 大樓這個門就充當了網關的角色, 大門通常都有看門員 ,看門員會作哪些事情呢?web
首先全部想見老闆的人確定都得從這個門進(統一入口), 這個門至關於將辦公室和外界隔離了,主要爲了保護裏面的安全以及正常工做, 來到這個門以後, 門衛確定會讓你出示相關證件(鑑權檢驗), 意思就是判斷你要見老闆這個請求是否合理, 若是不合理直接就拒絕了, 讓你回家等消息 , 若是鑑權以後, 發現你找老闆其實只是爲了和他談談兩元店的生意, 門衛會跟你說這個用不着找老闆, 你去集團投資部就好了(動態路由, 將請求路由到不一樣的後端集羣中), 此時會對你進行一些包裝,例如給你出具一個訪問證相似的,而後告訴你路該怎麼走,等等。spring
你看看,網關的做用是否是就是這三個, 最終目的就是減小你與集團的耦合,具體到計算機上就是減小客戶端與服務端的耦合,若是沒有網關意味着全部請求都會直接調用服務器上的資源,這樣耦合太強了,服務器出了問題,客戶端會直接報錯, 例如老闆換工做的地方了,若是沒有網關你直接去原來的地方找, 確定會被告知老闆不在這兒。數據庫
當使用單體應用程序架構時,客戶端(Web 或移動端)經過向後端應用程序發起一次 REST 調用來獲取數據。負載均衡器將請求路由給 N 個相同的應用程序實例中的一個。而後應用程序會查詢各類數據庫表,並將響應返回給客戶端。微服務架構下,單體應用被切割成多個微服務,若是將全部的微服務直接對外暴露,勢必會出現安全方面的各類問題,另外內外耦合嚴重。編程
客戶端能夠直接向每一個微服務發送請求,其問題主要以下:後端
服務端的各個服務直接暴露給客戶端調用勢必會引發各類問題。同時,服務端的各個服務可擴展和伸縮性不好。API 網關是微服務架構中的基礎組件,位於接入層之下和業務服務層之上,如前所述的這些功能適合在 API 網關實現。
回到咱們服務器上,下面圖介紹了網關(Gateway)做用,可知 Gateway 方式下的架構,能夠細到爲每個服務的實例配置一個本身的 Gateway,也能夠粗到爲一組服務配置一個,甚至能夠粗到爲整個架構配置一個接入的 Gateway。因而,整個系統架構的複雜度就會變得簡單可控起來。
這張圖展現了一個多層 Gateway 架構,其中有一個總的 Gateway 接入全部的流量(流量網關),並分發給不一樣的子系統,還有第二級 Gateway 用於作各個子系統的接入 Gateway(業務網關)。能夠看到,網關所管理的服務粒度可粗可細。經過網關,咱們能夠把分佈式架構組織成一個星型架構,由網絡對服務的請求進行路由和分發。下面來聊聊好的網關應該具有哪些功能,也就是網關設計模式。
一個網關須要有如下的功能:
網關必定要有請求路由的功能。這樣一來,對於調用端來講,也是一件很是方便的事情。由於調用端不須要知道本身須要用到的其它服務的地址,所有統一地交給 Gateway 來處理。
爲了可以代理後面的服務,並把請求路由到正確的位置上,網關應該有服務註冊功能,也就是後端的服務實例能夠把其提供服務的地址註冊、取消註冊。通常來講,註冊也就是註冊一些 API 接口。好比,HTTP 的 Restful 請求,能夠註冊相應 API 的 URI、方法、HTTP 頭。 這樣,Gateway 就能夠根據接收到的請求中的信息來決定路由到哪個後端的服務上。
由於一個網關能夠接收多個服務實例,因此網關還須要在各個對等的服務實例上作負載均衡策略。簡單點就是直接 Round-Robin 輪詢,複雜點的能夠設置上權重進行分發,再複雜一點還能夠作到 session 粘連。
網關還能夠把彈力設計中的那些異步、重試、冪等、流控、熔斷、監視等均可以實現進去。這樣,一樣能夠像 Service Mesh 那樣,讓應用服務只關心本身的業務邏輯(或是說數據面上的事)而不是控制邏輯(控制面)。
SSL 加密及證書管理、Session 驗證、受權、數據校驗,以及對請求源進行惡意攻擊的防範。錯誤處理越靠前的位置就是越好,因此,網關能夠作到一個全站的接入組件來對後端的服務進行保護。固然,網關還能夠作更多更有趣的事情,好比:灰度發佈、API聚合、API編排。
灰度發佈
網關徹底能夠作到對相同服務不一樣版本的實例進行導流,還能夠收集相關的數據。這樣對於軟件質量的提高,甚至產品試錯都有很是積極的意義。
API 聚合
使用網關能夠將多個單獨請求聚合成一個請求。在微服務體系的架構中,由於服務變小了,因此一個明顯的問題是,客戶端可能須要屢次請求才能獲得全部的數據。這樣一來,客戶端與後端之間的頻繁通訊會對應用程序的性能和規模產生很是不利的影響。因而,咱們可讓網關來幫客戶端請求多個後端的服務(有些場景下徹底能夠併發請求),而後把後端服務的響應結果拼裝起來,回傳給客戶端(固然,這個過程也能夠作成異步的,但這須要客戶端的配合)。
API 編排
一樣在微服務的架構下,要走完一個完整的業務流程,咱們須要調用一系列 API,就像一種工做流同樣,這個事徹底能夠經過網頁來編排這個業務流程。咱們可能經過一個 DSL 來定義和編排不一樣的 API,也能夠經過像 AWS Lambda 服務那樣的方式來串聯不一樣的 API。
網關設計重點主要是三個, 高性能、高可用、高擴展:
在技術設計上,網關不該該也不能成爲性能的瓶頸。對於高性能,最好使用高性能的編程語言來實現,如 C、C++、Go 和 Java。網關對後端的請求,以及對前端的請求的服務必定要使用異步非阻塞的 I/O 來確保後端延遲不會致使應用程序中出現性能問題。C 和 C++ 能夠參看 Linux 下的 epoll 和 Windows 的 I/O Completion Port 的異步 IO 模型,Java 下如 Netty、Spring Reactor 的 NIO 框架。
由於全部的流量或調用通過網關,因此網關必須成爲一個高可用的技術組件,它的穩定直接關係到了全部服務的穩定。網關若是沒有設計,就會成變一個單點故障。所以,一個好的網關至少要作到如下幾點。
由於網關須要承接全部的業務流量和請求,因此必定會有或多或少的業務邏輯。而咱們都知道,業務邏輯是多變和不肯定的。好比,須要在網關上加入一些和業務相關的東西。所以,一個好的 Gateway 還須要是能夠擴展的,並能進行二次開發的。固然,像 Nginx 那樣經過 Module 進行二次開發的當然能夠。
另外,在運維方面,網關應該有如下幾個設計原則。
另外,由於網關是爲用戶請求和後端服務的橋接裝置,因此須要考慮一些安全方面的事宜。具體以下:
流量網關,顧名思義就是控制流量進入集羣的網關,有不少工做須要在這一步作,對於一個服務集羣,勢必有不少非法的請求或者無效的請求,這時候要將請求拒之門外,下降集羣的流量壓力。
定義全局性的、跟具體的後端業務應用和服務徹底無關的策略網關就是上圖所示的架構模型——流量網關。流量網關一般只專一於全局的Api管理策略,好比全局流量監控、日誌記錄、全侷限流、黑白名單控制、接入請求到業務系統的負載均衡等,有點相似防火牆。Kong 就是典型的流量網關。
下面是kong的架構圖,來自官網:
這裏須要補充一點的是,業務網關通常部署在流量網關以後、業務系統以前,比流量網關更靠近業務系統。一般API網指的是業務網關。 有時候咱們也會模糊流量網關和業務網關,讓一個網關承擔全部的工做,因此這二者之間並無嚴格的界線。
當一個單體應用被拆分紅許許多多的微服務應用後,也帶來了一些問題。一些與業務非強相關的功能,好比權限控制、日誌輸出、數據加密、熔斷限流等,每一個微服務應用都須要,所以存在着大量重複的代碼實現。並且因爲系統的迭代、人員的更替,各個微服務中這些功能的實現細節出現了較大的差別,致使維護成本變高。另外一方面,原先單體應用下很是容易作的接口管理,在服務拆分後沒有了一個集中管理的地方,沒法統計已存在哪些接口、接口定義是什麼、運行狀態如何。
網關就是爲了解決上述問題。做爲微服務體系中的核心基礎設施,通常須要具有接口管理、協議適配、熔斷限流、安全防禦等功能,各類開源的網關產品(好比 zuul)都提供了優秀高可擴展性的架構、能夠很方便的實現咱們須要的一些功能、好比鑑權、日誌監控、熔斷限流等。
與流量網關相對應的就是業務網關,業務網關更靠近咱們的業務,也就是與服務器應用層打交道,那麼有不少應用層須要考慮的事情就能夠依託業務網關,例如在線程模型、協議適配、熔斷限流,服務編排等。下面看看業務網關體系結構:
圖片來自:業務網關的落地實踐
從這個途中能夠看出業務網關主要職責以及所作的事情, 目前業務網關比較成熟的 API 網關框架產品有三個 分別是:Zuul一、Zuul2 和 SpringCloud Gateway, 後面再進行對比。
既然對比,就先宏觀上對各類網關有一個瞭解,後面再挑一些經常使用的或者說應用普遍的詳細瞭解。
目前常見的開源網關大體上按照語言分類有以下幾類:
按照使用數量、成熟度等來劃分,主流的有 4 個:
OpenResty是一個流量網關,根據前面對流量網關的介紹就能夠知道流量網關的指責。
OpenResty基於 Nginx 與 Lua 的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用於方便地搭建可以處理超高併發、擴展性極高的動態 Web 應用、Web 服務和動態網關。
經過揉和衆多設計良好的 Nginx 模塊,OpenResty 有效地把 Nginx 服務器轉變爲一個強大的 Web 應用服務器,基於它開發人員可使用 Lua 編程語言對 Nginx 核心以及現有的各類 Nginx C 模塊進行腳本編程,構建出能夠處理一萬以上併發請求的極端高性能的 Web 應用
OpenResty 最先是順應 OpenAPI 的潮流作的,因此 Open 取自「開放」之意,而Resty即是 REST 風格的意思。雖而後來也能夠基於 ngx_openresty 實現任何形式的 web service 或者傳統的 web 應用。
也就是說 Nginx 再也不是一個簡單的靜態網頁服務器,也再也不是一個簡單的反向代理了。第二代的 openresty 致力於經過一系列 nginx 模塊,把nginx擴展爲全功能的 web 應用服務器。
ngx_openresty 是用戶驅動的項目,後來也有很多國內用戶的參與,從 openresty.org 的點擊量分佈上看,國內和國外的點擊量基本持平。
ngx_openresty 目前有兩大應用目標:
Kong基於OpenResty開發,也是流量層網關, 是一個雲原生、快速、可擴展、分佈式的Api 網關。繼承了OpenResty的高性能、易擴展性等特色。Kong經過簡單的增長機器節點,能夠很容易的水平擴展。同時功能插件化,可經過插件來擴展其能力。並且在任何基礎架構上均可以運行。具備如下特性:
Kong解決了什麼問題
當咱們決定對應用進行微服務改造時,應用客戶端如何與微服務交互的問題也隨之而來,畢竟服務數量的增長會直接致使部署受權、負載均衡、通訊管理、分析和改變的難度增長。
面對以上問題,API GATEWAY是一個不錯的解決方案,其所提供的訪問限制、安全、流量控制、分析監控、日誌、請求轉發、合成和協議轉換功能,能夠解放開發者去把精力集中在具體邏輯的代碼,而不是把時間花費在考慮如何解決應用和其餘微服務連接的問題上。
圖片來自Kong官網:
能夠看到Kong解決的問題。專一於全局的Api管理策略,全局流量監控、日誌記錄、全侷限流、黑白名單控制、接入請求到業務系統的負載均衡等。
Kong的優勢以及性能
在衆多 API GATEWAY 框架中,Mashape 開源的高性能高可用API網關和API服務管理層——KONG(基於 NGINX+Lua)特色尤其突出,它能夠經過插件擴展已有功能,這些插件(使用 lua 編寫)在API請求響應循環的生命週期中被執行。於此同時,KONG自己提供包括 HTTP 基本認證、密鑰認證、CORS、TCP、UDP、文件日誌、API請求限流、請求轉發及 NGINX 監控等基本功能。目前,Kong 在 Mashape 管理了超過 15,000 個 API,爲 200,000 開發者提供了每個月數十億的請求支持。
Kong架構
Kong提供一些列的服務,這就不得不談談內部的架構:
首先最底層是基於Nginx, Nginx是高性能的基礎層, 一個良好的負載均衡、反向代理器,而後在此基礎上增長Lua腳本庫,造成了OpenResty,攔截請求, 響應生命週期,能夠經過Lua編寫腳本,因此插件比較豐富。
關於Kong的一些插件庫以及如何配置,能夠參考簡書:開源API網關係統(Kong教程)入門到精通
Zuul是全部從設備和web站點到Netflix流媒體應用程序後端請求的前門。做爲一個邊緣服務應用程序,Zuul被構建來支持動態路由、監視、彈性和安全性。它還能夠根據須要將請求路由到多個Amazon自動伸縮組。
Zuul使用了一系列不一樣類型的過濾器,使咱們可以快速靈活地將功能應用到服務中。
過濾器
過濾器是Zuul的核心功能。它們負責應用程序的業務邏輯,能夠執行各類任務。
Zuul提供了一個動態讀取、編譯和運行這些過濾器的框架。過濾器之間不直接通訊,而是經過每一個請求特有的RequestContext共享狀態。
下面是Zuul的一些過濾器:
Incoming
Incoming過濾器在請求被代理到Origin以前執行。這一般是執行大部分業務邏輯的地方。例如:認證、動態路由、速率限制、DDoS保護、指標。
Endpoint
Endpoint過濾器負責基於incoming過濾器的執行來處理請求。Zuul有一個內置的過濾器(ProxyEndpoint),用於將請求代理到後端服務器,所以這些過濾器的典型用途是用於靜態端點。例如:健康檢查響應,靜態錯誤響應,404響應。
Outgoing
Outgoing過濾器在從後端接收到響應之後執行處理操做。一般狀況下,它們更多地用於造成響應和添加指標,而不是用於任何繁重的工做。例如:存儲統計信息、添加/剝離標準標題、向實時流發送事件、gziping響應。
過濾器類型
下面是與一個請求典型的生命週期對應的標準的過濾器類型:
這些過濾器幫助咱們執行如下功能:
Zuul 1.0 請求生命週期
Netflix宣佈了通用API網關Zuul的架構轉型。Zuul本來採用同步阻塞架構,轉型後叫做Zuul2,採用異步非阻塞架構。Zuul2和Zuul1在架構方面的主要區別在於,Zuul2運行在異步非阻塞的框架上,好比Netty。Zuul1依賴多線程來支持吞吐量的增加,而Zuul 2使用的Netty框架依賴事件循環和回調函數。
Zuul 2.0 架構圖
上圖是Zuul2的架構,和Zuul1沒有本質區別,兩點變化:
Inbound Filters : 路由到 Origin 以前執行,能夠用於身份驗證、路由和裝飾請求
Endpoint Filters : 可用於返回靜態響應,不然內置的ProxyEndpoint過濾器將請求路由到Origin
Outbound Filters : 從Origin那裏獲取響應後執行,能夠用於度量、裝飾用戶的響應或添加自定義header
有兩種類型的過濾器:sync 和 async。由於Zuul是運行在一個事件循環之上的,所以歷來不要在過濾中阻塞。若是你非要阻塞,能夠在一個異步過濾器中這樣作,而且在一個單獨的線程池上運行,不然可使用同步過濾器。
上文提到過Zuul2開始採用了異步模型
優點是異步非阻塞模式啓動的線程不多,基本上一個CPU core上只需啓一個事件環處理線程,它使用的線程資源就不多,上下文切換(Context Switch)開銷也少。非阻塞模式能夠接受的鏈接數大大增長,能夠簡單理解爲請求來了只須要進隊列,這個隊列的容量能夠設得很大,只要不超時,隊列中的請求都會被依次處理。
不足,異步模式讓編程模型變得複雜。一方面Zuul2自己的代碼要比Zuul1複雜不少,Zuul1的代碼比較容易看懂,Zuul2的代碼看起來就比較費勁。另外一方面異步模型沒有一個明確清晰的請求->處理->響應執行流程(call flow),它的流程是經過事件觸發的,請求處理的流程隨時可能被切換斷開,內部實現要經過一些關聯id機制才能把整個執行流再串聯起來,這就給開發調試運維引入了不少複雜性,好比你在IDE裏頭調試異步請求流就很是困難。另外ThreadLocal機制在這種異步模式下就不能簡單工做,由於只有一個事件環線程,不是每一個請求一個線程,也就沒有線程局部的概念,因此對於CAT這種依賴於ThreadLocal才能工做的監控工具,調用鏈埋點就很差搞(實際能夠工做但須要進行特殊處理)。
整體上,異步非阻塞模式比較適用於IO密集型(IO bound)場景,這種場景下系統大部分時間在處理IO,CPU計算比較輕,少許事件環線程就能處理。
Zuul 與 Zuul 2 性能對比
圖片來源:Zuul's Journey to Non-Blocking
Netflix給出了一個比較模糊的數據,大體Zuul2的性能比Zuul1好20%左右,這裏的性能主要指每節點每秒處理的請求數。爲何說模糊呢?由於這個數據受實際測試環境,流量場景模式等衆多因素影響,你很難復現這個測試數據。即使這個20%的性能提高是確實的,其實這個性能提高也並不大,和異步引入的複雜性相比,這20%的提高是否值得是個問題。Netflix自己在其博文\(^2\)和ppt\(^1\)中也是有點含糊其詞,甚至自身都有一些疑問的。
SpringCloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在爲微服務架構提供一種簡單有效的統一的 API 路由管理方式。
SpringCloud Gateway 做爲 Spring Cloud 生態系統中的網關,目標是替代 Zuul,在Spring Cloud 2.0以上版本中,沒有對新版本的Zuul 2.0以上最新高性能版本進行集成,仍然仍是使用的Zuul 2.0以前的非Reactor模式的老版本。而爲了提高網關的性能,SpringCloud Gateway是基於WebFlux框架實現的,而WebFlux框架底層則使用了高性能的Reactor模式通訊框架Netty。
Spring Cloud Gateway 的目標,不只提供統一的路由方式,而且基於 Filter 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。
Spring Cloud Gateway 底層使用了高性能的通訊框架Netty。
SpringCloud Gateway 特徵
SpringCloud官方,對SpringCloud Gateway 特徵介紹以下:
(1)基於 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
(2)集成 Hystrix 斷路器
(3)集成 Spring Cloud DiscoveryClient
(4)Predicates 和 Filters 做用於特定路由,易於編寫的 Predicates 和 Filters
(5)具有一些網關的高級功能:動態路由、限流、路徑重寫
從以上的特徵來講,和Zuul的特徵差異不大。SpringCloud Gateway和Zuul主要的區別,仍是在底層的通訊框架上。
簡單說明一下上文中的三個術語:
Filter(過濾器)
和Zuul的過濾器在概念上相似,可使用它攔截和修改請求,而且對上游的響應,進行二次處理。過濾器爲org.springframework.cloud.gateway.filter.GatewayFilter類的實例。
Route(路由)
網關配置的基本組成模塊,和Zuul的路由配置模塊相似。一個Route模塊由一個 ID,一個目標 URI,一組斷言和一組過濾器定義。若是斷言爲真,則路由匹配,目標URI會被訪問。
Predicate(斷言):
這是一個 Java 8 的 Predicate,可使用它來匹配來自 HTTP 請求的任何內容,例如 headers 或參數。斷言的輸入類型是一個 ServerWebExchange。
網關 | 限流 | 鑑權 | 監控 | 易用性 | 可維護性 | 成熟度 |
---|---|---|---|---|---|---|
Spring Cloud Gateway | 能夠經過IP,用戶,集羣限流,提供了相應的接口進行擴展 | 普通鑑權、auth2.0 | Gateway Metrics Filter | 簡單易用 | spring系列可擴展強,易配置 可維護性好 | spring社區成熟,但gateway資源較少 |
Zuul2 | 能夠經過配置文件配置集羣限流和單服務器限流亦可經過filter實現限流擴展 | filter中實現 | filter中實現 | 參考資料較少 | 可維護性較差 | 開源不久,資料少 |
OpenResty | 須要lua開發 | 須要lua開發 | 須要開發 | 簡單易用,可是須要進行的lua開發不少 | 可維護性較差,未來須要維護大量lua腳本 | 很成熟資料不少 |
Kong | 根據秒,分,時,天,月,年,根據用戶進行限流。可在原碼的基礎上進行開發 | 普通鑑權,Key Auth鑑權,HMAC,auth2.0 | 可上報datadog,記錄請求數量,請求數據量,應答數據量,接收於發送的時間間隔,狀態碼數量,kong內運行時間 | 簡單易用,api轉發經過管理員接口配置,開發須要lua腳本 | "可維護性較差,未來須要維護大量lua庫 | 相對成熟,用戶問題彙總,社區,插件開源 |
一、Zuul's Journey to Non-Blocking
二、Zuul 2 : The Netflix Journey to Asynchronous, Non-Blocking Systems