微服務架構下網關的技術選型

1、簡介

當使用單體應用程序架構時,客戶端(Web 或移動端)通過向後端應用程序發起一次 REST 調用來獲取數據。負載均衡器將請求路由給 N 個相同的應用程序實例中的一個。然後應用程序會查詢各種數據庫表,並將響應返回給客戶端。微服務架構下,單體應用被切割成多個微服務,如果將所有的微服務直接對外暴露,勢必會出現安全方面的各種問題,另外內外耦合嚴重。

客戶端可以直接向每個微服務發送請求,其問題主要如下:

服務端的各個服務直接暴露給客戶端調用勢必會引起各種問題。同時,服務端的各個服務可擴展和伸縮性很差。API 網關是微服務架構中的基礎組件,位於接入層之下和業務服務層之上,如前所述的這些功能適合在 API 網關實現。

1.1 什麼是網關?

網關的角色是作爲一個 API 架構,用來保護、增強和控制對於 API 服務的訪問。它是一個處於應用程序或服務(提供 REST API 接口服務)之前的系統,用來管理授權、訪問控制和流量限制等。這樣 REST API 接口服務就被網關保護起來,對所有的調用者透明。因此,隱藏在 API 網關後面的業務系統就可以專注於創建和管理服務,無需關心這些策略性的請求。

1.2 API 網關的四大職能

1.3 微服務下網關作用

下面圖介紹了網關 (Gateway) 作用,可知 Gateway 方式下的架構,可以細到爲每一個服務的實例配置一個自己的 Gateway,也可以粗到爲一組服務配置一個,甚至可以粗到爲整個架構配置一個接入的 Gateway。於是,整個系統架構的複雜度就會變得簡單可控起來。

這張圖展示了一個多層 Gateway 架構,其中有一個總的 Gateway 接入所有的流量 (流量網關),並分發給不同的子系統,還有第二級 Gateway 用於做各個子系統的接入 Gateway(業務網關 )。可以看到,網關所管理的服務粒度可粗可細。通過網關,我們可以把分佈式架構組織成一個星型架構,由網絡對服務的請求進行路由和分發。下面來聊聊好的網關應該具備哪些功能,也就是網關設計模式。

2 、網關設計思路

API 網關並不是一個典型的業務系統,而是一個爲了讓業務系統更專注於業務本身,給 API 服務提供更多附加能力的一箇中間層。一個網關需要有以下的功能:
  1. 請求路由

    網關一定要有請求路由的功能。這樣一來,對於調用端來說,也是一件非常方便的事情。因爲調用端不需要知道自己需要用到的其它服務的地址,全部統一地交給 Gateway 來處理。

  2. 服務註冊

    爲了能夠代理後面的服務,並把請求路由到正確的位置上,網關應該有服務註冊功能,也就是後端的服務實例可以把其提供服務的地址註冊、取消註冊。一般來說,註冊也就是註冊一些 API 接口。比如,HTTP 的 Restful 請求,可以註冊相應 API 的 URI、方法、HTTP 頭。這樣,Gateway 就可以根據接收到的請求中的信息來決定路由到哪一個後端的服務上。

  3. 負載均衡

    因爲一個網關可以接收多個服務實例,所以網關還需要在各個對等的服務實例上做負載均衡策略。簡單點就是直接 Round-Robin 輪詢,複雜點的可以設置上權重進行分發,再複雜一點還可以做到 session 粘連。

  4. 彈力設計

    網關還可以把彈力設計中的那些異步、重試、冪等、流控、熔斷、監視等都可以實現進去。這樣,同樣可以像 Service Mesh 那樣,讓應用服務只關心自己的業務邏輯(或是說數據面上的事)而不是控制邏輯(控制面)。

  5. 安全方面

    SSL 加密及證書管理、Session 驗證、授權、數據校驗,以及對請求源進行惡意攻擊的防範。錯誤處理越靠前的位置就是越好,所以,網關可以做到一個全站的接入組件來對後端的服務進行保護。當然,網關還可以做更多更有趣的事情,比如:灰度發佈、API 聚合、API 編排。

  6. 灰度發佈

    網關完全可以做到對相同服務不同版本的實例進行導流,還可以收集相關的數據。這樣對於軟件質量的提升,甚至產品試錯都有非常積極的意義。

  7. API 聚合

    使用網關可以將多個單獨請求聚合成一個請求。在微服務體系的架構中,因爲服務變小了,所以一個明顯的問題是,客戶端可能需要多次請求才能得到所有的數據。這樣一來,客戶端與後端之間的頻繁通信會對應用程序的性能和規模產生非常不利的影響。於是,我們可以讓網關來幫客戶端請求多個後端的服務(有些場景下完全可以併發請求),然後把後端服務的響應結果拼裝起來,回傳給客戶端(當然,這個過程也可以做成異步的,但這需要客戶端的配合)。

  8. API 編排

    同樣在微服務的架構下,要走完一個完整的業務流程,我們需要調用一系列 API,就像一種工作流一樣,這個事完全可以通過網頁來編排這個業務流程。我們可能通過一個 DSL 來定義和編排不同的 API,也可以通過像 AWS Lambda 服務那樣的方式來串聯不同的 API。

3、  網關設計重點

網關設計重點主要是三個, 高性能、高可用、高擴展:

3.1 高性能

在技術設計上,網關不應該也不能成爲性能的瓶頸。對於高性能,最好使用高性能的編程語言來實現,如 C、C++、Go 和 Java。網關對後端的請求,以及對前端的請求的服務一定要使用異步非阻塞的 I/O 來確保後端延遲不會導致應用程序中出現性能問題。C 和 C++ 可以參看 Linux 下的 epoll 和 Windows 的 I/O Completion Port 的異步 IO 模型,Java 下如 Netty、Spring Reactor 的 NIO 框架。

3.2 高可用

因爲所有的流量或調用經過網關,所以網關必須成爲一個高可用的技術組件,它的穩定直接關係到了所有服務的穩定。網關如果沒有設計,就會成變一個單點故障。因此,一個好的網關至少要做到以下幾點。

3.3 高擴展

因爲網關需要承接所有的業務流量和請求,所以一定會有或多或少的業務邏輯。而我們都知道,業務邏輯是多變和不確定的。比如,需要在網關上加入一些和業務相關的東西。因此,一個好的 Gateway 還需要是可以擴展的,並能進行二次開發的。當然,像 Nginx 那樣通過 Module 進行二次開發的固然可以。

另外,在運維方面 ,網關應該有以下幾個設計原則。

4、網關設計注意事項

  1. 不要在網關中的代碼裏內置聚合後端服務的功能,而應考慮將聚合服務放在網關核心代碼之外。可以使用 Plugin 的方式,也可以放在網關後面形成一個 Serverless 服務。

  2. 網關應該靠近後端服務,並和後端服務使用同一個內網,這樣可以保證網關和後端服務調用的低延遲,並可以減少很多網絡上的問題。這裏多說一句,網關處理的靜態內容應該靠近用戶(應該放到 CDN 上),而網關和此時的動態服務應該靠近後端服務。

  3. 網關也需要做容量擴展,所以需要成爲一個集羣來分擔前端帶來的流量。這一點,要麼通過 DNS 輪詢的方式實現,要麼通過 CDN 來做流量調度,或者通過更爲底層的性能更高的負載均衡設備。

  4. 對於服務發現,可以做一個時間不長的緩存,這樣不需要每次請求都去查一下相關的服務所在的地方。當然,如果你的系統不復雜,可以考慮把服務發現的功能直接集成進網關中。

  5. 爲網關考慮 bulkhead 設計方式。用不同的網關服務不同的後端服務,或是用不同的網關服務前端不同的客戶。

  6. 保持大規模的 inbound 請求接入能力(長短鏈接),比如基於 Netty 實現。

  7. 最大限度地複用 outbound 的 HTTP 連接能力,比如基於 httpClietn4 的異步實現。

  8. 方便靈活地實現安全、驗證、過濾、聚合、限流、監控等各種策略。

另外,因爲網關是爲用戶請求和後端服務的橋接裝置,所以需要考慮一些安全方面的事宜。具體如下:
  1. 加密數據 。可以把 SSL 相關的證書放到網關上,由網關做統一的 SSL 傳輸管理。

  2. 校驗用戶的請求 。一些基本的用戶驗證可以放在網關上來做,比如用戶是否已登錄,用戶請求中的 token 是否合法等。但是,我們需要權衡一下,網關是否需要校驗用戶的輸入。因爲這樣一來,網關就需要從只關心協議頭,到需要關心協議體。而協議體中的東西一方面不像協議頭是標準的,另一方面解析協議體還要耗費大量的運行時間,從而降低網關的性能。對此,我想說的是,看具體需求,一方面如果協議體是標準的,那麼可以幹;另一方面,對於解析協議所帶來的性能問題,需要做相應的隔離。

  3. 檢測異常訪問 。網關需要檢測一些異常訪問,比如,在一段比較短的時間內請求次數超過一定數值;還比如,同一客戶端的 4xx 請求出錯率太高…… 對於這樣的一些請求訪問,網關一方面要把這樣的請求屏蔽掉,另一方面需要發出警告,有可能會是一些比較重大的安全問題,如被黑客攻擊。

5、流量網關

流量網關,顧名思義就是控制流量進入集羣的網關,有很多工作需要在這一步做,對於一個服務集羣,勢必有很多非法的請求或者無效的請求,這時候要將請求拒之門外,降低集羣的流量壓力。

定義全局性的、跟具體的後端業務應用和服務完全無關的策略網關就是上圖所示的架構模型——流量網關。流量網關通常只專注於全局的 Api 管理策略,比如全局流量監控、日誌記錄、全侷限流、黑白名單控制、接入請求到業務系統的負載均衡等,有點類似防火牆。Kong 就是典型的流量網關。另外,搜索公衆號 GitHub 猿後臺回覆 “賺錢”,獲取一份驚喜禮包。

下面是 kong 的架構圖,來自官網:

這裏需要補充一點的是,業務網關一般部署在流量網關之後、業務系統之前,比流量網關更靠近業務系統。通常 API 網指的是業務網關。有時候我們也會模糊流量網關和業務網關,讓一個網關承擔所有的工作,所以這兩者之間並沒有嚴格的界線。

6、業務網關

當一個單體應用被拆分成許許多多的微服務應用後,也帶來了一些問題。一些與業務非強相關的功能,比如權限控制、日誌輸出、數據加密、熔斷限流等,每個微服務應用都需要,因此存在着大量重複的代碼實現。而且由於系統的迭代、人員的更替,各個微服務中這些功能的實現細節出現了較大的差異,導致維護成本變高。另一方面,原先單體應用下非常容易做的接口管理,在服務拆分後沒有了一個集中管理的地方,無法統計已存在哪些接口、接口定義是什麼、運行狀態如何。

網關就是爲了解決上述問題。作爲微服務體系中的核心基礎設施,一般需要具備接口管理、協議適配、熔斷限流、安全防護等功能,各種開源的網關產品(比如 zuul)都提供了優秀高可擴展性的架構、可以很方便的實現我們需要的一些功能、比如鑑權、日誌監控、熔斷限流等。

與流量網關相對應的就是業務網關,業務網關更靠近我們的業務,也就是與服務器應用層打交道,那麼有很多應用層需要考慮的事情就可以依託業務網關,例如在線程模型、協議適配、熔斷限流,服務編排等。下面看看業務網關體系結構:

從這個圖中可以看出業務網關主要職責以及所做的事情, 目前業務網關比較成熟的 API 網關框架產品有三個 分別是:Zuul1、Zuul2 和 SpringCloud Gateway, 後面再進行對比。

7、常見網關對比

目前常見的開源網關大致上按照語言分類有如下幾類:

按照使用數量、成熟度等來劃分,主流的有 4 個:

7.1 OpenResty

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 目前有兩大應用目標:

  1. 通用目的的 web 應用服務器。在這個目標下,現有的 web 應用技術都可以算是和 OpenResty 或多或少有些類似,比如 Nodejs, PHP 等等。ngx_openresty 的性能(包括內存使用和 CPU 效率)算是最大的賣點之一。

  2. Nginx 的腳本擴展編程,用於構建靈活的 Web 應用網關和 Web 應用防火牆。有些類似的是 NetScaler。其優勢在於 Lua 編程帶來的巨大靈活性。

7.2 Kong

Kong 基於 OpenResty 開發,也是流量層網關, 是一個雲原生、快速、可擴展、分佈式的 Api 網關。繼承了 OpenResty 的高性能、易擴展性等特點。Kong 通過簡單的增加機器節點,可以很容易的水平擴展。同時功能插件化,可通過插件來擴展其能力。而且在任何基礎架構上都可以運行。具有以下特性:

Kong 解決了什麼問題

當我們決定對應用進行微服務改造時,應用客戶端如何與微服務交互的問題也隨之而來,畢竟服務數量的增加會直接導致部署授權、負載均衡、通信管理、分析和改變的難度增加。

面對以上問題,API GATEWAY 是一個不錯的解決方案,其所提供的訪問限制、安全、流量控制、分析監控、日誌、請求轉發、合成和協議轉換功能,可以解放開發者去把精力集中在具體邏輯的代碼,而不是把時間花費在考慮如何解決應用和其他微服務鏈接的問題上。

從下圖可以看到 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 架構

首先最底層是基於 Nginx, Nginx 是高性能的基礎層, 一個良好的負載均衡、反向代理器,然後在此基礎上增加 Lua 腳本庫,形成了 OpenResty,攔截請求, 響應生命週期,可以通過 Lua 編寫腳本,所以插件比較豐富。

7.3 Zuul2.0

上圖是 Zuul2 的架構,和 Zuul1 沒有本質區別,兩點變化:

  1. 前端用 Netty Server 代替 Servlet,目的是支持前端異步。後端用 Netty Client 代替 Http Client,目的是支持後端異步。

  2. 過濾器換了一下名字,用 Inbound Filters 代替 Pre-routing Filters,用 Endpoint Filter 代替 Routing Filter,用 Outbound Filters 代替 Post-routing Filters。

Zuul2 採用了異步模型

優勢::是異步非阻塞模式啓動的線程很少,基本上一個 CPU core 上只需啓一個事件環處理線程,它使用的線程資源就很少,上下文切換 (Context Switch) 開銷也少。非阻塞模式可以接受的連接數大大增加,可以簡單理解爲請求來了只需要進隊列,這個隊列的容量可以設得很大,只要不超時,隊列中的請求都會被依次處理。

不足: 異步模式讓編程模型變得複雜。一方面 Zuul2 本身的代碼要比 Zuul1 複雜很多,Zuul1 的代碼比較容易看懂,Zuul2 的代碼看起來就比較費勁。另一方面異步模型沒有一個明確清晰的請求 -> 處理 -> 響應執行流程 (call flow),它的流程是通過事件觸發的,請求處理的流程隨時可能被切換斷開,內部實現要通過一些關聯 id 機制才能把整個執行流再串聯起來,這就給開發調試運維引入了很多複雜性,比如你在 IDE 裏頭調試異步請求流就非常困難。另外 ThreadLocal 機制在這種異步模式下就不能簡單工作,因爲只有一個事件環線程,不是每個請求一個線程,也就沒有線程局部的概念,所以對於 CAT 這種依賴於 ThreadLocal 才能工作的監控工具,調用鏈埋點就不好搞 (實際可以工作但需要進行特殊處理)。

總體上,異步非阻塞模式比較適用於 IO 密集型 (IO bound) 場景,這種場景下系統大部分時間在處理 IO,CPU 計算比較輕,少量事件環線程就能處理。

7.4 Spring Cloud Gateway

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)具備一些網關的高級功能:動態路由、限流、路徑重寫

8、幾種網關的對比

基於不同的業務場景,選擇不同的 API 網關組件,應對不同的系統流量和併發數。不同的業務場景,在技術選型上也是及其重要的一環。例如:Kong 的性能雖然非常不錯,適合做流量網關,但是對於複雜的業務系統不建議用 Kong,因爲會給系統的性能帶來缺陷。再如 SpringCloud GateWay/Zuul2 對於 Java 技術棧來說比較方便,但是對於 lua 開發語言不方便。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/km-zKShHOFRKp2SkSt8XGg