百億流量微服務閘道器的設計與實現

技術瑣話發表於2022-12-05

本文從百億流量交易系統微服務閘道器(API Gateway)的現狀和麵臨的問題出發,闡述微服務架構與 API 閘道器的關係,理順流量閘道器與業務閘道器的脈絡,分享API閘道器知識與經驗。

API閘道器概述

“電腦科學領域的任何問題都可以透過增加一個間接的中間層來解決。”

——David Wheeler

分散式服務架構、微服務架構與 API 閘道器

1. 什麼是API閘道器(API Gateway)

其實,閘道器跟面向服務架構(Service Oriented Architecture,SOA)和微服務架構(MicroServicesArchitecture,MSA)有很深的淵源。

十多年以前,銀行等金融機構完成全國業務系統大集中以後,分散的系統都變得集中,也帶來了各種問題:業務發展過快如何應對,對接系統過多如何整合和管理。為了解決這些問題,業界實現了作用於渠道與業務系統之間的中間層閘道器,即綜合前置系統,由其適配各類渠道和業務,處理各種協議接入、路由與報文轉換、同步非同步呼叫等操作,如圖7-1所示。

百億流量微服務閘道器的設計與實現                           

圖7-1

人們基於SOA的理念,在綜合前置的基礎上,進一步增加了服務的後設資料管理、註冊、中介、編排、治理等功能,逐漸形成了企業服務匯流排(ESB,EnterpriseService Bus)。例如普元公司推出的PrimetonESB就是一個由本書作者之一參與開發的匯流排系統,如圖7-2所示。

百億流量微服務閘道器的設計與實現

圖7-2

面向服務架構(SOA)是一種建設企業IT生態系統的架構指導思想。SOA的關注點是服務,服務最基本的業務功能單元由平臺中立性的介面契約來定義。透過將業務系統服務化,可以將不同模組解耦,各種異構系統間可以輕鬆實現服務呼叫、訊息交換和資源共享。不同於以往的孤立業務系統,SOA強調整個企業IT生態環境是一個大的整體。整個IT生態中的所有業務服務構成了企業的核心IT資源。各個系統的業務拆解為不同粒度和層次的模組和服務,服務可以組裝到更大的粒度,不同來源的服務可以編排到同一個處理流程中,實現非常複雜的整合場景和更加豐富的業務功能。

SOA從更高的層次對整個企業IT生態進行統一的設計與管理,應用軟體被劃分為具有不同功能的服務單元,並透過標準的軟體介面把這些服務聯絡起來,以SOA架構實現的企業應用可以更靈活快速地響應企業的業務變化,實現新舊軟體資產的整合和複用,降低軟體整體擁有成本。

當然基於ESB這種集中式管理的SOA方案也存在種種問題,特別是在面向網際網路技術領域的爆發式發展的情況下。

2. 分散式服務架構、微服務架構與API閘道器

近年來,隨著網際網路技術的飛速發展,為了解決以ESB為代表的集中式管理的SOA方案的種種問題,以Apache Dubbo(2011年開源後)與Spring Cloud為代表的分散式服務化技術的出現,給了SOA實現的另外一個選擇:去中心化的分散式服務架構(DSA)。分散式服務架構技術不再依賴於具體的服務中心容器技術(比如ESB),而是將服務定址和呼叫完全分開,這樣就不需要透過容器作為服務代理。

之後又在此基礎上隨著REST、Docker容器化、領域建模、自動化測試運維等領域的發展,逐漸形成了微服務架構(MSA)。在微服務架構裡,服務的粒度被進一步細分,各個業務服務可以被獨立地設計、開發、測試、部署和管理。這時,各個獨立部署單元可以選擇不同的開發測試團隊維護,可以使用不同的程式語言和技術平臺進行設計,但是要求必須使用一種語言和平臺無關的服務協議作為各個單元之間的通訊方式,如圖7-3所示。

百億流量微服務閘道器的設計與實現

圖7-3

在微服務架構中,由於系統和服務的細分,導致系統結構變得非常複雜,RESTAPI由於其簡單、高效、跨平臺、易開發、易測試、易整合,成為不二選擇。此時一個類似綜合前置的系統就產生了,這就是API閘道器(API Gateway)。API閘道器作為分散在各個業務系統微服務的API聚合點和統一接入點,外部請求透過訪問這個接入點,即可訪問內部所有的REST API服務。

跟SOA/ESB類似,企業內部向外暴露的所有業務服務能力,都可以透過API閘道器上管理的API服務得以體現,所以API閘道器上也就聚合了企業所有直接對外提供的IT業務能力。

3. API閘道器的技術趨勢

Spring Cloud和SOA非常火,MSA、gRPC、Gateway都有著非常高的關注度,透過GitHub的搜尋來看,Gateway型別的專案也非常熱門。

從上可以看到,前10頁的100個專案,使用Go語言實現的Gateway差不多佔一半,從語言分類上來看:Go>Node.js/JavaScript>Java>Lua>C/C++>PHP>Python/Ruby/Perl。

API閘道器的定義、職能與關注點

1. API閘道器的定義

閘道器的角色是作為一個API架構,用來保護、增強和控制對於API服務的訪問(The role of a Gateway in anAPI architecture is to protect, enrich and control access to API services.)。

引用自。

API閘道器是一個處於應用程式或服務(提供REST API介面服務)之前的系統,用來管理授權、訪問控制和流量限制等,這樣REST API介面服務就被API閘道器保護起來,對所有的呼叫者透明。因此,隱藏在API閘道器後面的業務系統就可以專注於建立和管理服務,而不用去處理這些策略性的基礎設施。

這樣,閘道器係統就可以代理業務系統的業務服務API。此時閘道器接收外部其他系統的服務呼叫請求,也需要訪問後端的實際業務服務。在接收請求的同時,可以實現安全相關的系統保護措施。在訪問後端業務服務的時候,可以根據相關的請求資訊做出判斷,路由到特定的業務服務上,或者呼叫多個服務後聚合成新的資料返回給呼叫方。閘道器係統也可以把請求的資料做一些過濾和預處理,同理也可以把返回給呼叫者的資料做一些過濾和預處理,即根據需要對請求頭/響應頭、請求報文/響應報文做一些修改。如果不做這些額外的處理,則簡單直接代理服務API功能,我們稱之為透傳。

同時,由於REST API的語言無關性,基於API閘道器,後端服務可以是任何異構系統,不論Java、.NET、Python,還是PHP、ROR、Node.js等,只要支援REST API,就可以被API閘道器管理起來。

2. API閘道器的職能

API閘道器的職能如圖7-4所示。

百億流量微服務閘道器的設計與實現

圖7-4

一般來說,API閘道器有四大職能。

  • 請求接入:作為所有API介面服務請求的接入點,管理所有的接入請求。

  • 業務聚合:作為所有後端業務服務的聚合點,所有的業務服務都可以在這裡被呼叫。

  • 中介策略:實現安全、驗證、路由、過濾、流控、快取等策略,進行一些必要的中介處理。

  • 統一管理:提供配置管理工具,對所有API服務的呼叫生命週期和相應的中介策略進行統一管理。

3. API閘道器的關注點

API閘道器並不是一個典型的業務系統,而是一個為了讓業務系統更專注於業務服務本身,給API服務提供更多附加能力的一箇中間層。

在設計和實現API閘道器時,需要考慮兩個目標:

(1)開發維護簡單,節約人力成本和維護成本。即應選擇成熟的簡單可維護的技術體系。

(2)高效能,節約裝置成本,提高系統吞吐能力。要求我們需要針對API閘道器的特點進行一些特定的設計和權衡。

當併發量小的時候,這些都不是問題。一旦系統的API訪問量非常大,這些都會成為關鍵的問題。

海量併發的API閘道器最重要的三個關注點:

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

(2)最大限度地複用outbound的HTTP連線能力,比如基於HttpClient4的非同步HttpClient實現。

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

API閘道器的分類與技術分析

1. API閘道器的分類

如果對上述的目標和關注點進行更深入的思考,那麼所有需要考慮的問題和功能可以分為兩類。

  • 一類是全域性性的,跟具體的後端業務系統和服務完全無關的部分,比如安全策略、全域性性流控策略、流量分發策略等。

  • 一類是針對具體的後端業務系統,或者是服務和業務有一定關聯性的部分,並且一般被直接部署在業務服務的前面。

隨著網際網路的複雜業務系統的發展,這兩類功能集合逐漸形成了現在常見的兩種閘道器係統:流量閘道器和業務閘道器,如圖7-5所示。

百億流量微服務閘道器的設計與實現

圖7-5

2. 流量閘道器與WAF

我們定義全域性性的、跟具體的後端業務系統和服務完全無關的策略閘道器,即為流量閘道器。這樣流量閘道器關注全域性流量的穩定與安全,比如防止各類SQL隱碼攻擊、黑白名單控制、接入請求到業務系統的負載均衡等,通常有如下通用性的具體功能:

  • 全域性性流控;

  • 日誌統計;

  • 防止SQL隱碼攻擊;

  • 防止Web攻擊;

  • 遮蔽工具掃描;

  • 黑白名單控制。

透過這個功能清單,我們可以發現,流量閘道器的功能跟Web應用防火牆(WAF)非常類似。WAF一般是基於Nginx/OpenResty的ngx_lua模組開發的Web應用防火牆。

一般WAF的程式碼很簡單,專注於使用簡單、高效能和輕量級。簡單地說就是在Nginx本身的代理能力以外,新增了安全相關功能。用一句話描述其原理,就是解析HTTP請求(協議解析模組),規則檢測(規則模組),做不同的防禦動作(動作模組),並將防禦過程(日誌模組)記錄下來。

一般的WAF具有如下功能:

  • 防止SQL隱碼攻擊、部分溢位、fuzzing測試、XSS/SSRF等Web攻擊;

  • 防止Apache Bench之類壓力測試工具的攻擊;

  • 遮蔽常見的掃描駭客工具,比如掃描器;

  • 禁止圖片附件類目錄執行許可權、防止webshell上傳;

  • 支援IP白名單和黑名單功能,直接拒絕黑名單的IP訪問;

  • 支援URL白名單,定義不需要過濾的URL;

  • 支援User-Agent的過濾、支援CC攻擊防護、限制單個URL指定時間的訪問次數;

  • 支援支援Cookie過濾,URL與URL引數過濾;

  • 支援日誌記錄,將所有拒絕的操作記錄到日誌中。

以上WAF的內容主要參考如下兩個專案:

流量閘道器的開源例項還可以參考著名的開源專案Kong(基於OpenResty)。

3. 業務閘道器

我們定義針對具體的後端業務系統,或者是服務和業務有一定關聯性的策略閘道器,即為業務閘道器。比如,針對某個系統、某個服務或某個使用者分類的流控策略,針對某一類服務的快取策略,針對某個具體系統的許可權驗證方式,針對某些使用者條件判斷的請求過濾,針對具體幾個相關API的資料聚合封裝,等等。

業務閘道器一般部署在流量閘道器之後、業務系統之前,比流量閘道器更靠近業務系統。我們大部分情況下說的API閘道器,狹義上指的是業務閘道器。如果系統的規模不大,我們也會將兩者合二為一,使用一個閘道器來處理所有的工作。

開源閘道器的分析與調研

常見的開源閘道器介紹

常見的開源閘道器如圖7-6所示。

百億流量微服務閘道器的設計與實現

圖7-6

目前常見的開源閘道器大致上按照語言分類有如下幾類。

  • Nginx+Lua:Open Resty、Kong、Orange、Abtesting Gateway等;

  • Java:Zuul/Zuul 2、Spring Cloud Gateway、Kaazing KWG、gravitee、Dromara soul等;

  • Go:Janus、fagongzi、Grpc-Gateway;

  • .NET:Ocelot;

  • Node.js:Express Gateway、MicroGateway。

按照使用範圍、成熟度等來劃分,主流的有4個:OpenResty、Kong、Zuul/Zuul 2、Spring Cloud Gateway,此外fagongzi API閘道器最近也獲得不少關注。

1. Nginx+Lua閘道器

OpenResty

專案地址:

OpenResty基於Nginx,整合了Lua語言和Lua的各種工具庫、可用的第三方模組,這樣我們就在Nginx既有的高效HTTP處理的基礎上,同時獲得了Lua提供的動態擴充套件能力。因此,我們可以做出各種符合我們需要的閘道器策略的Lua指令碼,以其為基礎實現閘道器係統。

Kong

專案地址:與

Kong基於OpenResty,是一個雲原生、快速、可擴充套件、分散式的微服務抽象層(MicroserviceAbstraction Layer),也叫API閘道器(API Gateway),在Service Mesh裡也叫API中介軟體(API Middleware)。

Kong開源於2015年,核心價值在於其高效能和擴充套件性。從全球5000強的組織統計資料來看,Kong是現在依然在維護的、在生產環境使用最廣泛的閘道器。

核心優勢如下。

  • 可擴充套件:可以方便地透過新增節點實現水平擴充套件,這意味著可以在很低的延遲下支援很大的系統負載。

  • 模組化:可以透過新增新的外掛來擴充套件Kong的能力,這些外掛可以透過RESTful Admin API來安裝和配置。

  • 在任何基礎架構上執行:Kong在任何地方都能執行,比如在雲或混合環境中部署Kong,或者單個/全球的資料中心。

ABTestingGateway

專案地址:

ABTestingGateway是一個可以動態設定分流策略的閘道器,關注與灰度釋出相關的領域,基於Nginx和ngx-lua開發,使用Redis作為分流策略資料庫,可以實現動態排程功能。


ABTestingGateway是新浪微博內部的動態路由系統dygateway的一部分,目前已經開源。在以往的基於Nginx實現的灰度系統中,分流邏輯往往透過rewrite階段的if和rewrite指令等實現,優點是效能較高,缺點是功能受限、容易出錯,以及轉發規則固定,只能靜態分流。ABTestingGateway則採用 ngx-lua,透過啟用lua-shared-dict和lua-resty-lock作為系統快取和快取鎖,系統獲得了較為接近原生Nginx轉發的效能。

功能特性如下。

  • 支援多種分流方式,目前包括iprange、uidrange、uid尾數和指定uid分流;

  • 支援多級分流,動態設定分流策略,即時生效,無須重啟;

  • 可擴充套件性,提供了開發框架,開發者可以靈活新增新的分流方式,實現二次開發;

  • 高效能,壓測資料接近原生Nginx轉發;

  • 灰度系統配置寫在Nginx配置檔案中,方便管理員配置;

  • 適用於多種場景:灰度釋出、AB測試和負載均衡等。

據瞭解,美團網內部的Oceanus也是基於Nginx和ngx-lua擴充套件實現的,主要提供服務註冊與發現、動態負載均衡、視覺化管理、定製化路由、安全反扒、Session ID複用、熔斷降級、一鍵截流和效能統計等功能。

2. 基於Java語言的閘道器

Zuul/Zuul2

專案地址:

Zuul是Netflix開源的API閘道器係統,它的主要設計目標是動態路由、監控、彈性和安全。

Zuul的內部原理可以簡單看作很多不同功能filter的集合(作為對比,ESB也可以簡單被看作管道和過濾器的集合)。這些過濾器(filter)可以使用Groovy或其他基於JVM的指令碼編寫(當然Java也可以編寫),放置在指定的位置,然後可以被Zuul Server輪詢,發現變動後動態載入並實時生效。Zuul目前有1.x和2.x兩個版本,這兩個版本的差別很大。

Zuul 1.x基於同步I/O,也是Spring Cloud全家桶的一部分,可以方便地配合Spring Boot/SpringCloud配置和使用。

在Zuul 1.x裡,Filter的種類和處理流程如圖7-7所示,最主要的就是pre、routing、post這三種過濾器,分別作用於呼叫業務服務API之前的請求處理、直接響應、呼叫業務服務API之後的響應處理。

Zuul 2.x最大的改進就是基於Netty Server實現了非同步I/O來接入請求,同時基於Netty Client實現了到後端業務服務API的請求。這樣就可以實現更高的效能、更低的延遲。此外也調整了Filter型別,將原來的三個核心Filter顯式命名為Inbound Filter、Endpoint Filter和Outbound Filter,如圖7-8所示。

百億流量微服務閘道器的設計與實現

圖7-7

百億流量微服務閘道器的設計與實現

圖7-8

Zuul 2.x的核心功能:服務發現、負載均衡、連線池、狀態分類、重試、請求憑證、HTTP/2、TLS、代理協議、GZip、WebSocket。

SpringCloud Gateway

專案地址:

Spring Cloud Gateway基於Java 8、Spring 5.0、Spring Boot 2.0、Project Reactor,發展得比Zuul 2要早,目前也是Spring Cloud全家桶的一部分。

Spring Cloud Gateway可以看作一個Zuul 1.x的升級版和代替品,比Zuul 2更早地使用Netty實現非同步I/O,從而實現了一個簡單、比Zuul 1.x更高效的、與Spring Cloud緊密配合的API閘道器。

Spring Cloud Gateway裡明確地區分了Router和Filter,內建了非常多的開箱即用功能,並且都可以透過Spring Boot配置或手工編碼鏈式呼叫來使用。

比如內建了10種Router,直接配置就可以隨心所欲地根據Header、Path、Host或Query來做路由。

核心特性:

  • 透過請求引數匹配路由;

  • 透過斷言和過濾器實現路由;

  • 與Hystrix熔斷整合;

  • 與Spring Cloud DiscoveryClient整合;

  • 非常方便地實現斷言和過濾器;

  • 請求限流;

  • 路徑重寫。

graviteeGateway

專案地址:與

KaazingWebSocket Gateway

專案地址:

Kaazing WebSocket Gateway是一個專門針對和處理WebSocket的閘道器,宣稱提供世界一流的企業級WebSocket服務能力。具體如下特性:

  • 標準WebSocket支援,支援全雙工的雙向資料投遞;

  • 線性擴充套件,無狀態架構意味著可以部署更多機器來擴充套件服務能力;

  • 驗證,鑑權,單點登入支援,跨域訪問控制;

  • SSL/TLS加密支援;

  • WebSocket keepalive和TCP半開半關探測;

  • 透過負載均衡和叢集實現高可用;

  • Docker支援;

  • JMS/AMQP等支援;

  • IP白名單;

  • 自動重連和訊息可靠接受保證;

  • Fanout處理策略;

  • 實時快取等。

Dromara soul

專案地址:。

Soul是一個非同步的、高效能的、跨語言的、響應式的API閘道器,提供了統一的HTTP訪問。

  • 支援各種語言,無縫整合Dubbo和SpringCloud;

  • 豐富的外掛支援鑑權、限流、熔斷、防火牆等;

  • 閘道器多種規則動態配置,支援各種策略配置;

  • 外掛熱插拔,易擴充套件;

  • 支援叢集部署,支援A/B Test。

3. 基於Go語言的閘道器

fagongzi

專案地址:

fagongzi Gateway是一個Go實現的功能全面的API閘道器,自帶了一個Rails實現的Web UI管理介面。

功能特性:流量控制、熔斷、負載均衡、服務發現、外掛機制、路由(分流,複製流量)、API聚合、API引數校驗、API訪問控制(黑白名單)、API預設返回值、API定製返回值、API結果Cache、JWT認證、API Metric匯入Prometheus、API失敗重試、後端Server的健康檢查、開放管理API(gRPC、RESTful)、支援WebSocket協議。

Janus

專案地址:

Janus是一個輕量級的API閘道器和管理平臺,能實現控制誰、什麼時候、如何訪問這些REST API,同時它也記錄了所有的訪問互動細節和錯誤。使用Go實現API閘道器的一個好處在於,一般只需要一個單獨的二進位制檔案即可執行,沒有複雜的依賴關係。功能特性:

  • 熱載入配置,不需要重啟閘道器程式;

  • HTTP連線的優雅關閉;

  • 支援OpenTracing,從而可以進行分散式跟蹤;

  • 支援HTTP/2;

  • 可以針對每一個API實現斷路器;

  • 重試機制;

  • 流控,可以針對每一個使用者或key;

  • CORS過濾,可以針對具體的API;

  • 多種開箱即用的驗證協議支援,比如JWT、OAuth 2.0和Basic Auth;

  • Docker Image支援。

4. .NET

Ocelot

專案地址:

功能特性:路由、請求聚合、服務發現(基於Consul或Eureka)、服務Fabric、WebSockets、驗證與鑑權、流控、快取、重試策略與QoS、負載均衡、日誌與跟蹤、請求頭、Query字串轉換、自定義的中間處理、配置和管理REST API。

5. Node.js

Express Gateway

專案地址:

Express Gateway是一個基於Node.js開發,使用Express和Express中介軟體實現的REST API閘道器。

功能特性:

  • 動態中心化配置;

  • API消費者和憑證管理;

  • 外掛機制;

  • 分散式資料儲存;

  • 命令列工具CLI。

MicroGateway

專案地址:

與https://developer.ibm.com/apiconnect

StrongLoop是IBM的一個子公司,MicroGateway閘道器基於Node.js/Express和Nginx構建,作為IBM API Connect,同時也是IBM雲生態的一部分。MicroGateway是一個聚焦於開發者,可擴充套件的閘道器框架,它可以增強我們對微服務和API的訪問能力。

核心特性:

  • 安全和控制,基於Swagger(OpenAPI)規範;

  • 內建了多種閘道器策略,API Key驗證、流控、OAuth 2.0、JavaScript指令碼支援;

  • 使用Swagger擴充套件(API Assembly)實現閘道器策略(安全、路由、整合等);

  • 方便地自定義閘道器策略。

此外,MicroGateway還有幾個特性:

  • 透過整合Swagger,實現基於Swagger API定義的驗證能力;

  • 使用datastore來保持需要處理的API資料模型;

  • 使用一個流式引擎來處理多種策略,使API設計者可以更好地控制API的生命週期。

核心架構如圖7-9所示。

百億流量微服務閘道器的設計與實現

圖7-9

四大開源閘道器的對比分析

1. OpenResty/Kong/Zuul 2/SpringCloud Gateway重要特性對比

各項指標對比如表7-1所示。

百億流量微服務閘道器的設計與實現

以限流功能為例:

  • Spring Cloud Gateway目前提供了基於Redis的Ratelimiter實現,使用的演算法是令牌桶演算法,透過YAML檔案進行配置;

  • Zuul2可以透過配置檔案配置叢集限流和單伺服器限流,也可透過Filter實現限流擴充套件;

  • OpenResty可以使用resty.limit.count、resty.limit.conn、resty.limit.req來實現限流功能,可實現漏桶或令牌通演算法;

  • Kong擁有基礎限流元件,可在基礎元件原始碼基礎上進行Lua開發。

對Zuul/Zuul 2/Spring Cloud Gateway的一些功能點分析可以參考Spring Cloud Gateway作者Spencer Gibb的文章:。

2. OpenResty/Kong/Zuul 2/SpringCloudGateway效能測試對比

分別使用3臺4Core、16GB記憶體的機器,作為API服務提供者、Gateway、壓力機,使用wrk作為效能測試工具,對OpenResty/Kong/Zuul 2/SpringCloud Gateway進行簡單小報文下的效能測試,如圖7-10所示。

百億流量微服務閘道器的設計與實現

圖7-10

圖中縱座標軸是QPS,橫軸是一個Gateway的資料,每根線是一個場景下的不同閘道器資料,測試結論如下:

  • 實測情況是效能SCG~Zuul 2 << OpenResty~< Kong << Direct(直連);

  • Spring Cloud Gateway、Zuul 2的效能差不多,大概是直連的40%;

  • OpenResty、Kong的效能差不多,大概是直連的60%~70%;

  • 大併發下,例如模擬200併發使用者、1000併發使用者時,Zuul 2會有很大機率返回出錯。

開源閘道器的技術總結

1. 開源閘道器的測試分析

脫離場景談效能,都是“耍流氓”。效能就像溫度,不同的場合下標準是不一樣的。同樣是18攝氏度,老人覺得冷,年輕人覺得合適,企鵝覺得熱,冰箱裡的蔬菜可能容易壞了。

同樣基準條件下,不同的引數和軟體,相對而言的橫向比較才有價值。比如同樣的機器(比如16GB記憶體/4核),同樣的Server(用Spring Boot,配置路徑為api/hello,返回一個helloworld),同樣的壓測方式和工具(比如用wrk,10個執行緒,20個併發連線)。我們測試直接訪問Server得到的極限QPS(QPS-Direct,29K);配置了一個Spring Cloud Gateway做閘道器訪問的極限QPS(QPS-SCG,11K);同樣方式配置一個Zuul 2做閘道器壓測得到的極限QPS(QPS-Zuul2,13K);Kong得到的極限QPS(QPS-Kong,21K);OpenResty得到的極限QPS(QPS-OR,19K)。這個對比就有意義了。

Kong的效能非常不錯,非常適合做流量閘道器,並且對於service、route、upstream、consumer、plugins的抽象,也是自研閘道器值得借鑑的。

對於複雜系統,不建議業務閘道器用Kong,或者更明確地說是不建議在Java技術棧的系統深度定製Kong或OpenResty,主要是出於工程性方面的考慮。舉個例子:假如我們有多個不同業務線,鑑權方式五花八門,都是與業務多少有點相關的。這時如果把鑑權在閘道器實現,就需要維護大量的Lua指令碼,引入一個新的複雜技術棧是一個成本不低的事情。

Spring Cloud Gateway/Zuul 2對於Java技術棧來說比較方便,可以依賴業務系統的一些通用的類庫。Lua不方便,不光是語言的問題,更是複用基礎設施的問題。另外,對於閘道器係統來說,效能不會差一個數量級,問題不大,多加2臺機器就可以“搞定”。

從測試的結果來看,如果後端API服務的延遲都較低(例如2ms級別),直連的吞吐量假如是100QPS,Kong可以達到60QPS,OpenResty是50QPS,Zuul 2和Spring CloudGateway大概是35QPS,如果服務本身的延遲(latency)大一點,那麼這些差距會逐步縮小。

目前來看Zuul 2的“坑”還是比較多的:

(1)剛出不久,不成熟,沒什麼文件,還沒有太多的實際應用案例。

(2)高併發時出錯率較高,1000併發時我們的測試場景有近50%的出錯率。

簡單使用或輕度定製業務閘道器係統,目前建議使用Spring CloudGateway作為基礎骨架。

2. 各類閘道器的Demo與測試

以上測試用到的模擬服務和閘道器Demo程式碼,大部分可以在這裡找到:

kimmking/atlantis。

我們使用Vert.x實現了一個簡單閘道器,效能跟Zuul 2和Spring Cloud Gateway差不多。另外也簡單模擬了一個Node.js做的閘道器Demo,加了keep-alive和pool,Demo的效能測試結果大概是直連的1/9,也就是Spring Cloud Gateway或Zuul 2的1/4左右。

百億流量交易系統API閘道器設計

百億流量交易系統API閘道器的現狀和麵臨問題

1. 百億流量系統面對的業務現狀

百億流量系統面對的業務現狀如圖7-11所示。

 

百億流量微服務閘道器的設計與實現

 圖7-11


我們目前面臨的現狀是日常十幾萬的併發線上長連線數(不算短連線),每天長連線總數為3000萬+,每天API的呼叫次數超過100億次,每天交易訂單數為1.5億個。

在這種情況下,API閘道器設計的一個重要目標就是:如何藉助API閘道器為各類客戶提供精準、專業、個性化的服務,保障客戶實時地獲得業務系統的資料和業務能力。

2. 閘道器係統與其他系統的關係

某交易系統的API閘道器係統與其他系統的關係大致如圖7-12所示。

百億流量微服務閘道器的設計與實現

圖7-12

3. 閘道器係統典型的應用場景

我們的API閘道器係統為Web端、移動App端客戶提供服務,也為大量API客戶提供API呼叫服務,同時支援REST API和WebSocket協議。

作為實時交易系統的前置系統,必須精準及時為客戶提供最新的行情和交易資訊。一旦出現資料的延遲或錯誤,都會給客戶造成無法挽回的損失。

另外針對不同的客戶和渠道,閘道器係統需要提供不同的安全、驗證、流控、快取策略,同時可以隨時聚合不同視角的資料進行預處理,保障系統的穩定可靠和資料的實時精確。

4. 交易系統API的特點

作為一個全球性的交易系統,我們的API特點總結如下。

  • 訪問非常集中:最核心的一組API佔據了訪問量的一半以上;

  • 訪問非常頻繁:QPS非常高,日均訪問量非常大;

  • 資料格式固定:交易系統處理的資料格式非常固定;

  • 報文資料量小:每次請求傳輸的資料一般不超過10KB;

  • 使用者全世界分佈:客戶分佈在全世界的各個國家;

  • 分內部呼叫和外部呼叫:除了API客戶直接呼叫的API,其他的API都是由內部其他系統呼叫的;

  • 7×24小時不間斷服務:系統需要提供高可用、不間斷的服務能力,以滿足不同時區客戶的交易和自動化策略交易;

  • 外部使用者有一定技術能力:外部API客戶,一般是整合我們的API,實現自己的交易系統。

5. 交易系統API閘道器面臨的問題

問題1:流量不斷增加。

如何合理控制流量,如何應對突發流量,如何最大限度地保障系統穩定,都是重要的問題。特別是閘道器作為一個直接面對客戶的系統,出現的任何問題都會放大百倍。很多千奇百怪的從來沒人遇到的問題隨時都可能出現。

問題2:閘道器係統越來越複雜。

現有的業務閘道器經過多年發展,裡面有大量的業務嵌入,並且存在多個不同的業務閘道器,相互之間沒有任何關係,也沒有沉澱出基礎設施。

同時技術債務太多,系統裡硬編碼實現了全域性性閘道器策略及很多業務規則,導致維護成本較大。

問題3:API閘道器管理比較困難。

海量併發下API的監控指標設計和資料的收集也是一個不小的問題。7×24小時執行的技術支援也導致維護成本較高。

問題4:選擇推送還是拉取。

使用短連線還是長連線,REST API還是WebSocket?業務渠道較多(多個不同產品線的Web、App、API等形成十幾個不同的渠道),導致使用者的使用行為難以控制。

業務閘道器的設計與最佳實踐

1. API閘道器1.0

我們的API閘道器1.0版本是多年前開發的,是直接使用OpenResty定製的,全域性的安全測試、流量的路由轉發策略、針對不同級別的限流等都是直接用Lua指令碼實現。

這樣就導致在經歷了業務飛速發展以後,系統裡存在非常多的相同功能或不同功能的Lua指令碼,每次上線或維護都需要找到受影響的其中幾個或幾十個Lua指令碼,進行策略調整,非常不方便,策略控制的粒度也不夠細。

2. API閘道器2.0

在區分了流量閘道器和業務閘道器以後,2017年開始實現了流量閘道器和業務閘道器的分離,流量閘道器繼續使用OpenResty定製,只保留少量全域性性、不經常改動的配置功能和對應的Lua指令碼。

業務閘道器使用Vert.x實現的Java系統,部署在流量閘道器和後端業務服務系統之間,利用Vert.x的響應式程式設計能力和非同步非阻塞I/O能力、分散式部署的擴充套件能力,初步解決了問題1和問題2,如圖7-13所示。

百億流量微服務閘道器的設計與實現

圖7-13

Vert.x是一個基於事件驅動和非同步非阻塞I/O、執行於JVM上的框架,如圖7-14所示。在Vert.x裡,Verticle是最基礎的開發和部署單元,不同的Vert.x可以透過Event Bus傳遞資料,進而方便地實現高併發效能的網路程式。關於Vert.x原理的分析可以參考阿里架構師宿何的blog:

百億流量微服務閘道器的設計與實現

圖7-14

Vert.x同時很好地支援了WebSocket協議,所以可以方便地實現支援REST API和WebSocket、完全非同步的閘道器係統,如圖7-15所示。

百億流量微服務閘道器的設計與實現

圖7-15

一個高效能的API閘道器係統,快取是必不可少的部分。無論分發冷熱資料,降低對業務系統的壓力,還是作為中間資料來源,為服務聚合提供高效可複用的業務資料,快取都發揮了巨大作用。

3. API閘道器的日常監控

我們使用多種工具對API進行監控和管理,包括全鏈路訪問跟蹤、連線數統計分析、全世界重要國家和城市的波測訪問統計。閘道器技術團隊每時每刻都關注著資料的變化趨勢。各個業務系統研發團隊每天安排專人關注自己系統的API效能(吞吐量和延遲),推進效能問題解決和持續最佳化。這就初步解決了問題3。

4. 推薦外部客戶使用WebSocket和API SDK

由於外部客戶需要自己透過API閘道器呼叫API服務來整合業務服務能力到自己的系統。各個客戶的技術能力和系統處理能力有較大差異,使用行為也不同。對於不斷髮展變動的交易業務資料,客戶呼叫API頻率太低會影響資料實時性,呼叫頻率太高則可能會浪費雙方的系統資源。同時利用WebSocket的訊息推送特點,我們可以在閘道器係統控制客戶接收訊息的頻率、單個使用者的連線數量等,隨時根據業務系統的情況動態進行策略調整。綜合考慮,WebSocket是一個比REST API更加實時可靠、更加易於管理的方式。另外對於習慣使用REST API的客戶,我們也透過將各種常見使用場景封裝成多種不同語言的API SDK(包括Java/C++/C#/Python),進而統一使用者的API呼叫方式和行為。在研發、產品、運營各方的配合下,逐步協助客戶使用WebSocket協議和API SDK,基本解決了問題4。

5. API閘道器的效能最佳化

API閘道器係統作為API服務的統一接入點,為了給使用者提供最優質的使用者體驗,必須長期做效能最佳化工作。不僅API閘道器自己做最佳化,同時可以根據監控情況,時刻發現各業務系統的API服務能力,以此為出發點,推動各個業務系統不斷最佳化API效能。

舉一個具體的例子,某個閘道器係統連線經常強烈抖動(如圖7-16所示),嚴重影響系統的穩定性、浪費系統資源,經過排除發現:

(1)有爬蟲IP不斷爬取我們的交易資料,而且這些IP所在網段都沒有在平臺產生任何實際交易,最高單爬蟲IP的每日新建連線近100萬次,平均每秒十幾次。

(2)有部分API客戶的程式存在bug,而且處理速度有限,不斷地重複“斷開並重新連線”,再嘗試重新對API資料進行處理,嚴重影響了客戶的使用者體驗。

針對如上分析,我們採取瞭如下處理方式:

(1)對於每天認定的爬蟲IP,加入黑名單,直接在流量閘道器限制其訪問我們的API閘道器。

(2)對於存在bug的API客戶,協助對方進行問題定位和bug修復,增強客戶使用信心。

(3)對於處理速度和技術能力有限的客戶,基於定製的WebSocket服務,使用滑動時間視窗演算法,在業務資料變化非常大時,對分發的訊息進行批次最佳化。

百億流量微服務閘道器的設計與實現

圖7-16

(4)對於未登入和識別身份的API呼叫,流量閘道器實現全域性的流控策略,增加快取時間和限制呼叫次數,保障系統穩定。

(5)業務閘道器根據API服務的重要等級和客戶的分類,進一步細化和實時控制閘道器策略,最大限度地保障核心業務和客戶的使用。

從監控圖表可以看到,最佳化之後的效果非常明顯,系統穩定,連線數平穩。

本文節選自《高可用可伸縮微服務架構:基於Dubbo、Spring Cloud和Service Mesh》一書,程超,梁桂釗,秦金衛,方誌斌,張逸等著

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31562044/viewspace-2651041/,如需轉載,請註明出處,否則將追究法律責任。

相關文章