1. 程式人生 > 實用技巧 >這樣講API閘道器,你應該能明白了吧!

這樣講API閘道器,你應該能明白了吧!

為了提高系統的效能和可靠性,將應用服務進行拆分微服務化。作為系統入口的 API 閘道器也逐漸成為了標配。

今天我們一起來看看 API 閘道器的設計思路,需要承載了哪些功能?以及如何選擇流行的 API 閘道器?

什麼是 API 閘道器

既然需要 API 閘道器為我所用,首先就讓我們來了解一下什麼是 API 閘道器。

什麼是API閘道器

閘道器一詞最早出現在網路裝置,比如兩個相互獨立的區域網之間通過路由器進行通訊,中間的路由被稱之為閘道器。

任何一個應用系統如果需要被其他系統呼叫,就需要暴露 API,這些 API 代表著一個一個的功能點。


如果兩個系統中間通訊,在系統之間加上一個中介者協助 API 的呼叫,這個中介者就是 API 閘道器。

對接兩個系統的 API閘道器


當然,API 閘道器可以放在兩個系統之間,同時也可以放在客戶端與服務端之間。

對接客戶端和服務端的 API 閘道器

知道了 API 閘道器的基本定義,再來看看為什麼我們要使用它。

為何要使用 API 閘道器

閘道器作為系統的唯一入口,也就是說,進入系統的所有請求都需要經過 API 閘道器。

當系統外部的應用或者客戶端訪問系統的時候,都會遇到這樣的情況:

  • 系統要判斷它們的許可權

  • 如果傳輸協議不一致,需要對協議進行轉換

  • 如果呼叫水平擴充套件的服務,需要做負載均衡

  • 一旦請求流量超出系統承受的範圍,需要做限流操作

  • 針對每個請求以及回覆,系統會記錄響應的日誌

也就是說,只要是涉及到對系統的請求,並且能夠從業務中抽離出來的功能,都有可能在閘道器上實現。

例如:協議轉換,負載均衡,請求路由,流量控制等等。後面我們會一一給大家介紹這些功能。

在瞭解 API 閘道器有哪些基本功能以後,來看看它可以服務於哪些系統或者客戶端。

API 閘道器服務定位

API 閘道器擁有處理請求的能力,從定位來看分為 5 類:

①面向WebApp,這部分的系統以網站和 H5 應用為主。通過前後端分離的設計,將大部分的業務功能都放在了後端,前面的 Web App 只展示頁面的內容。

②MobileApp,這裡的 Mobile 指的是 iOS 和 Android,設計思路和 WebApp 基本相同。

區別是 API 閘道器需要做一些移動裝置管理的工作(MDM)。例如:裝置的註冊,啟用,使用,淘汰等,全生命週期的管理。

由於移動裝置的特殊性,導致了我們在考慮移動裝置請求的時候,需要考慮請求,裝置,使用者之間的關係。

③面向合作伙伴的 OpenAPI,通常系統會給合作伙伴提供介面。這些介面會全部開放或者部分開發,在有條件限制(時間,流量)的情況下給合作伙伴訪問。因此需要更多考慮 API 閘道器的流量和安全以及協議轉換的管理。

④企業內部可擴充套件 API,給企業內部的其他部門或者專案使用,也可以作為中颱輸出的一部分,支援其他系統。這裡需要更多地考慮劃分功能邊界,認證和授權問題。

⑤面向 IOT 裝置,會接收來自 IOT 裝置的請求,特別是工業感測器等裝置。這裡需要考慮協議轉換和資料過濾。

API 閘道器架構

既然談了 API 閘道器的功能和定位,接下來說說它的架構:

API 網關係統架構圖

API 閘道器拆分成為 3 個系統:

  • Gateway-Core(核心)

  • Gateway-Admin(管理)

  • Gateway-Monitor(監控)

Gateway-Core 核心閘道器,負責接收客戶端請求,排程、載入和執行元件,將請求路由到上游服務端,並處理其返回的結果。

大多數的功能都在這一層完成,例如:驗證,鑑權,負載均衡,協議轉換,服務路由,資料快取。如果沒有其他兩個子系統,它也是可以單獨執行的。

Gateway-Admin 閘道器管理介面,可以進行 API、元件等系統基礎資訊的配置;例如:限流的策略,快取配置,告警設定。

Gateway-Monitor 監控日誌、生成各種運維管理報表、自動告警等;管理和監控系統主要是為核心系統服務的,起到支撐的作用。

API 閘道器技術原理

上面談到了閘道器的架構思路,這裡談幾點技術原理。平時我們在使用閘道器的時候,多注重其實現的功能。例如:路由,負載均衡,限流,快取,日誌,釋出等等。

實際上這些功能的背後有一些原理我們可以瞭解,這樣在應用功能的時候會更加篤定。下面是幾個原理分享給大家。

協議轉換

每個系統內部服務之間的呼叫,可以統一使用一種協議,例如:HTTP,GRPC。

假設每個系統使用的協議不同,那麼系統之間的呼叫或者資料傳輸,就存在協議轉換的問題了。如果解決這個問題呢?API 閘道器通過泛化呼叫的方式實現協議之間的轉化。

實際上就是將不同的協議轉換成“通用協議”,然後再將通用協議轉化成本地系統能夠識別的協議。

這一轉化工作通常在 API 閘道器完成。通用協議用得比較多的有 JSON,當然也有使用 XML 或者自定義 JSON 檔案的。

不同的協議需要轉化成共同語言進行傳輸

鏈式處理

設計模式中有一種責任鏈模式,它將“處理請求”和“處理步驟”分開。每個處理步驟,只關心這個步驟上需要做的處理操作,處理步驟存在先後順序。


訊息從第一個“處理步驟”流入,從最後一個“處理步驟”流出,每個步驟對經過的訊息進行處理,整個過程形成了一個鏈條。在 API 閘道器中也用到了類似的模式。

Zuul 閘道器過濾器鏈式處理

下面以 Zuul 為例,當訊息出入閘道器需要經歷一系列的過濾器。這些過濾器之間是有先後順序的,並且在每個過濾器需要進行的工作也是各不一樣:

  • PRE:前置過濾器,用來處理通用事務,比如鑑權,限流,熔斷降級,快取。並且可以通過 Custom 過濾器進行擴充套件。

  • ROUTING:路由過濾器,在這種過濾器中把使用者請求傳送給 Origin Server。它主要負責:協議轉化和路由的工作。

  • POST:後置過濾器,從 Origin Server 返回的響應資訊會經過它,再返回給呼叫者。在返回的 Response 上加入 Response Header,同時可以做 Response 的統計和日誌記錄。

  • ERROR:錯誤過濾器,當上面三個過濾器發生異常時,錯誤資訊會進到這裡,並對錯誤進行處理。

非同步請求

所有的請求通過 API 閘道器訪問應用服務,一旦吞吐量上去了,如何高效地處理這些請求?
拿 Zuul 為例,Zuul1 採用:一個執行緒處理一個請求的方式。執行緒負責接受請求,然後呼叫應用返回結果。
如果把網路請求看成一次 IO 操作的話,處理請求的執行緒,從接受請求,到服務返回響應,都是阻塞狀態。

同時,如果多個執行緒都處在這種狀態,會導致系統緩慢。因為每個閘道器能夠開啟的執行緒數量是有限的,特別是在訪問的高峰期。

每個執行緒處理一個請求
為了解決這個問題,Zuul2 啟動了非同步請求的機制。每個請求進入閘道器的時候,會被包裝成一個事件,CPU 核心會維持一個監聽器,不斷輪詢“請求事件”。
一旦,發現請求事件,就會呼叫對應的應用。獲取應用返回的資訊以後,按照請求的要求把資料/檔案放到指定的緩衝區,同時傳送一個通知事件,告訴請求端資料已經就緒,可以從這個緩衝獲取資料/檔案。
這個過程是非同步的,請求的執行緒不用一直等待資料的返回。它在請求完畢以後,就直接返回了,這時它可以做其他的事情。

當請求資料被 CPU 核心獲取,並且傳送到指定的資料緩衝區時,請求的執行緒會接到“資料返回”的通知,然後就直接使用資料,不用自己去做取資料的操作。

非同步請求處理,CPU 處理資料以後通知請求端
實現非同步處理請求有兩種模式,分別是:

  • Reactor

  • Proactor

Reactor 工作原理流水圖

Reactor:通過 handle_events 事件迴圈處理請求。使用者執行緒註冊事件處理器之後,可以繼續執行其他的工作(非同步),而 Reactor 執行緒負責呼叫核心的 Select 函式檢查 Socket 狀態。

當有 Socket 被啟用時(獲取網路資料),則通知相應的使用者執行緒,執行 handle_event 進行資料讀取、處理的工作。

Proactor 工作原理流水圖

Proactor:使用者執行緒使用 CPU 核心提供的非同步 IO 發起請求,請求發起以後立即返回。CPU 核心繼續執行使用者請求執行緒程式碼。
此時使用者執行緒已將 AsynchronousOperation(非同步處理)和 CompletionHandler(完成獲取資源)註冊到核心。之後作業系統開啟獨立的核心執行緒去處理 IO 操作。
當請求的資料到達時,由核心負責讀取 Socket(網路請求)中的資料,並寫入使用者指定的緩衝區中。
最後核心將資料和使用者執行緒註冊的 CompletionHandler 分發給內部 Proactor,Proactor 將 IO 完成的資訊通知給使用者執行緒(一般通過呼叫使用者執行緒註冊的完成事件處理函式),完成非同步 IO。

API 閘道器實現功能

說起對 API 閘道器的使用,我們還是對具體功能更加感興趣。讓我們一起來看看它實現了哪些功能

負載均衡

當閘道器後面掛接同一應用的多個副本時,每次使用者的請求都會通過閘道器的負載均衡演算法,路由到對應的服務上面。例如:隨機演算法,權重演算法,Hash 演算法等等。
如果上游服務採取微服務的架構,也可以和註冊中心合作實現動態的負載均衡。

當微服務動態掛載(動態擴容)的時候,可以通過服務註冊中心獲取微服務的註冊資訊,從而實現負載均衡。

Nginx+Lua+服務註冊中心實現動態負載均衡

路由選擇

這個不言而喻,閘道器可以根據請求的 URL 地址解析,知道需要訪問的服務。再通過路由表把請求路由到目標服務上去。

有時候因為網路原因,服務可能會暫時的不可用,這個時候我們希望可以再次對服務進行重試。

Zuul作為API閘道器將請求路由到上游伺服器

例如:Zuul 與 Spring Retry 合作完成路由重試。

#是否開啟重試功能
zuul.retryable=true
#對當前服務的重試次數
ribbon.MaxAutoRetries=2

流量控制

限流是 API 閘道器常用的功能之一,當上遊服務超出請求承載範圍,或者服務因為某種原因無法正常使用,都會導致服務處理能力下滑。
這個時候,API 閘道器作為“看門人”,就可以限制流入的請求,讓應用伺服器免受衝擊。

限流實際上就是限制流入請求的數量,其演算法不少,有令牌桶演算法,漏桶演算法,連線數限制等等。這裡我們就介紹三個常用的,一般通過 Nginx+Lua 來實現。

令牌桶限流

統一鑑權

訪問應用伺服器的請求都需要擁有一定許可權,如果說每訪問一個服務都需要驗證一次許可權,這個對效率是很大的影響。可以把許可權認證放到 API 閘道器來進行。
目前比較常見的做法是,使用者通過登入服務獲取 Token,把它存放到客戶端,在每次請求的時候把這個 Token 放入請求頭,一起傳送給伺服器。
API 閘道器要做的事情就是解析這個 Token,知道訪問者是誰(鑑定),他能做什麼/訪問什麼(許可權)。
說白了就是看訪問者能夠訪問哪些 URL,這裡根據許可權/角色定義一個訪問列表。
如果要實現多個系統的 OSS(Single Sign On 單點登入),API 閘道器需要和 CAS(Central Authentication Service 中心鑑權服務)做連線,來確定請求者的身份和許可權。

熔斷降級

當應用服務出現異常,不能繼續提供服務的時候,也就是說應用服務不可用了。作為 API 閘道器需要做出處理,把請求匯入到其他服務上。
或者對服務進行降級處理,例如:用兜底的服務資料返回客戶端,或者提示服務暫時不可用。
同時通過服務註冊中心,監聽存在問題的服務,一旦服務恢復,隨即恢復路由請求到該服務。

例如:Zuul 中提供了 ZuulFallbackProvider 介面來實現熔斷,它提供兩個方法,一個指明熔斷攔截的服務 getRoute,一個指定返回內容 ClientHttpResponse。

public  interface ZuulFallbackProvider {
   /**
     * The route this fallback will be used  for.
     * @return The route the fallback will be  used for.
     */
    public String getRoute();

    /**
     * Provides a fallback response.
     * @return The fallback response.
     */
    public  ClientHttpResponsefallbackResponse();
}

我們通過自定義的 Fallback 方法,並且將其指定給某個 Route 來實現該 Route 訪問出問題的熔斷處理。

主要繼承 ZuulFallbackProvider 介面來實現,ZuulFallbackProvider 預設有兩個方法,一個用來指明熔斷攔截哪個服務,一個定製返回內容。

API閘道器熔斷降級

釋出測試

在釋出版本的時候會採用:金絲雀釋出和藍綠髮布。作為 API 閘道器可以使用路由選擇和流量切換來協助上述行為。這裡以金絲雀釋出為例,看看 API 閘道器如何做路由轉換的。

假設將 4 個服務從 V1 更新到 V2 版本,這 4 個服務的流量請求由 1 個 API 閘道器管理。

那麼先將一臺服務與 API 閘道器斷開,部署 V2 版本的服務,然後 API 閘道器再將流量匯入到 V2 版本的服務上。

這裡流量的匯入可以是逐步進行的,一旦 V2 版本的服務趨於穩定。再如法炮製,將其他服務替換成 V2 版本。

金絲雀釋出一般先發 1 臺,或者一個小比例,例如 2% 的伺服器,主要做流量驗證用,也稱為金絲雀(Canary)測試(灰度測試)。

其來歷是,曠工下礦洞前,先放一隻金絲雀探查是否有毒氣,金絲雀釋出由此得名。

金絲雀測試需要完善的監控設施配合,通過監控指標反饋,觀察金絲雀的健康狀況,作為後續釋出或回滾的依據。

如果金絲測試通過,則把剩餘的 V1 版本全部升級為 V2 版本。如果金絲雀測試失敗,則直接回退金絲雀,釋出失敗。

快取資料

我們可以在 API 閘道器快取一些修改頻率不高的資料。例如:使用者資訊,配置資訊,通過服務定期重新整理這個快取就行了:

  • 使用者請求先訪問 API 閘道器,如果發現有快取資訊,直接返回給使用者。

  • 如果沒有發現快取資訊,回源到應用伺服器獲取資訊。

  • 另外,有一個快取更新服務,定期把應用伺服器中的資訊更新到閘道器本地快取中。

日誌記錄

通過 API 閘道器上的過濾器我們可以加入日誌服務,記錄請求和返回資訊。同時可以建立一個管理員的介面去監控這些資料。

日誌服務簡圖
日誌記錄了以後,可以做很多功能擴充套件。我們整理了以下幾點供大家參考:

  • 報表分析:針對服務訪問情況,提供視覺化展示。

  • 實時查詢:瞭解實時關鍵資訊,例如:吞吐量,併發數。在秒殺活動的時候,會特別關注。

  • 異常告警:針對關鍵引數進行監控,對於統計結果支援閾值報警,對接阿里雲通知中心、簡訊、釘釘進行告警。

  • 日誌投遞:將日誌進行歸檔,存放到檔案庫或者資料倉庫中,以便後期分析。

日誌記錄衍生的功能

流行 API閘道器對比

在介紹了 API 閘道器的功能以後,再來看看目前幾個流行的 API 閘道器專案。看看他們各自的特點,並且把他們做一個簡單的比較。這些閘道器目前都是開源的,大家可以有選擇地在專案中使用。

Kong

Kong 是 Mash ape 公司的開源專案,它是一個在 Nginx 中執行的 Lua 應用程式,並且可以通過 Lua-Nginx 模組實現擴充套件。
所以,可以通過外掛集合的方式定製功能,例如:HTTP 基本認證、金鑰認證、CORS(Cross-origin Resource Sharing,跨域資源共享)、TCP、UDP、日誌、API 限流、請求轉發以及監控,都是目前已有的外掛。

由於是基於 Nginx 的,所以可以對閘道器進行水平擴充套件,來應對大批量的網路請求。

Kong 架構圖
Kong 主要有三個元件:

  • KongServer :基於 Nginx 的伺服器,用來接收 API 請求。

  • ApacheCassandra/PostgreSQL:用來儲存操作資料。

  • Kongdashboard:UI 管理工具。

Traefik

Traefik 架構圖
Traefik 是 HTTP 反向代理和負載均衡器,可以輕鬆部署微服務,可以與現有的元件(Docker、Swarm,Kubernetes,Marathon,Consul,Etcd)做整合。
因為支援動態配置,所以它的伸縮性很好。不過它只支援 HTTP、HTTPS 和 GRPC。如果你需要 TCP 負載均衡,那麼您需要選擇其他方案了。

Ambassador

Ambassador架構圖
Ambassador 是一個基於 Envoy Proxy 構建的,Kubernetes 原生的開源微服務閘道器。
它在構建之初就致力於支援多個獨立的團隊,這些團隊需要為終端使用者快速釋出、監控和更新服務。
Ambassador 還具有 Kubernetes Ingress 和負載均衡的能力。它支援處理 Kubernetes Ingress Controller 和負載均衡等功能,可以與 Istio 無縫整合。

Zuul

Zuul2 結構圖
Zuul 是 Spring Cloud 全家桶中的微服務 API 閘道器。所有從裝置或網站來的請求都會經過 Zuul 到達後端的 Netflix 應用程式。
作為一個邊界性質的應用程式,Zuul 提供了動態路由、監控、彈性負載和安全功能。包括 Zuul1 和 Zuul2 兩個版本。

介紹了幾個開源 API 閘道器的基本資訊以後,我們從幾個維度對他們進行比較:

從開源社群活躍度來說,Kong 和 Traefik 較好;從成熟度來看,較好的是 Kong、Traefik;從架構優勢的擴充套件性來看,Kong 有豐富的外掛,Ambassador 也有外掛但不多,而 Zuul 是需要自研。
但 Zuul 由於與 Spring Cloud 整合,如果使用 Spring Cloud 的小夥伴可以考慮使用。

總結

API 閘道器是系統內外通訊的中介者。從定位上來說它服務 WebApp,MobileApp,合作伙伴 OpenAPI,企業內部可擴充套件 API,以及 IOT 裝置。
從架構設計角度來說,分為 Gateway-Core(核心)、Gateway-Admin(管理)、Gateway-Monitor(監控)三部分。
API 閘道器需要注意的技術原理有,協議轉換,鏈式處理以及非同步請求。它的應用比較廣泛,例如:負載均衡,路由選擇,流量控制,統一鑑權,熔斷降級,釋出測試,快取資料,日誌記錄等。
比較流行的開源 API閘道器有 Kong,Traefik,Ambassador,Zuul。從使用上來說他們各有千秋,可以根據專案的情況選取。

來源: 程式設計師DD, 程式設計師小灰,macrozheng