百億流量微服務網關的設計與實現
- 2019 年 10 月 4 日
- 筆記
本文從百億流量交易系統微服務網關(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類型的項目也非常熱門。
從https://github.com/search?o=desc&p=1&q=gateway&s=stars&type=Repositories上可以看到,前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.)。
引用自https://github.com/strongloop/microgateway。
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的內容主要參考如下兩個項目:
- https://github.com/unixhot/waf;
- https://github.com/loveshell/ngx_lua_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
項目地址:http://openresty.org/
OpenResty基於Nginx,集成了Lua語言和Lua的各種工具庫、可用的第三方模塊,這樣我們就在Nginx既有的高效HTTP處理的基礎上,同時獲得了Lua提供的動態擴展能力。因此,我們可以做出各種符合我們需要的網關策略的Lua腳本,以其為基礎實現網關係統。
Kong
項目地址:https://konghq.com/與https://github.com/kong/kong
Kong基於OpenResty,是一個雲原生、快速、可擴展、分佈式的微服務抽象層(MicroserviceAbstraction Layer),也叫API網關(API Gateway),在Service Mesh里也叫API中間件(API Middleware)。
Kong開源於2015年,核心價值在於其高性能和擴展性。從全球5000強的組織統計數據來看,Kong是現在依然在維護的、在生產環境使用最廣泛的網關。
核心優勢如下。
- 可擴展:可以方便地通過添加節點實現水平擴展,這意味着可以在很低的延遲下支持很大的系統負載。
- 模塊化:可以通過添加新的插件來擴展Kong的能力,這些插件可以通過RESTful Admin API來安裝和配置。
- 在任何基礎架構上運行:Kong在任何地方都能運行,比如在雲或混合環境中部署Kong,或者單個/全球的數據中心。
ABTestingGateway
項目地址:https://github.com/CNSRE/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
項目地址:https://github.com/Netflix/zuul
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
項目地址:https://github.com/spring-cloud/spring-cloud-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
項目地址:https://gravitee.io/與https://github.com/gravitee-io/gravitee-gateway
KaazingWebSocket Gateway
項目地址:
https://github.com/kaazing/gateway與https://kaazing.com/products/websocket-gateway/
Kaazing WebSocket Gateway是一個專門針對和處理WebSocket的網關,宣稱提供世界一流的企業級WebSocket服務能力。具體如下特性:
- 標準WebSocket支持,支持全雙工的雙向數據投遞;
- 線性擴展,無狀態架構意味着可以部署更多機器來擴展服務能力;
- 驗證,鑒權,單點登錄支持,跨域訪問控制;
- SSL/TLS加密支持;
- WebSocket keepalive和TCP半開半關探測;
- 通過負載均衡和集群實現高可用;
- Docker支持;
- JMS/AMQP等支持;
- IP白名單;
- 自動重連和消息可靠接受保證;
- Fanout處理策略;
- 實時緩存等。
Dromara soul
項目地址:https://github.com/Dromara/soul。
Soul是一個異步的、高性能的、跨語言的、響應式的API網關,提供了統一的HTTP訪問。
- 支持各種語言,無縫集成Dubbo和SpringCloud;
- 豐富的插件支持鑒權、限流、熔斷、防火牆等;
- 網關多種規則動態配置,支持各種策略配置;
- 插件熱插拔,易擴展;
- 支持集群部署,支持A/B Test。
3. 基於Go語言的網關
fagongzi
項目地址:https://github.com/fagongzi/gateway
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
項目地址:https://github.com/hellofresh/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
項目地址:https://github.com/ThreeMammals/Ocelot
功能特性:路由、請求聚合、服務發現(基於Consul或Eureka)、服務Fabric、WebSockets、驗證與鑒權、流控、緩存、重試策略與QoS、負載均衡、日誌與跟蹤、請求頭、Query字符串轉換、自定義的中間處理、配置和管理REST API。
5. Node.js
Express Gateway
項目地址:
https://github.com/ExpressGateway/express-gateway與https://www.express-gateway.io/
Express Gateway是一個基於Node.js開發,使用Express和Express中間件實現的REST API網關。
功能特性:
- 動態中心化配置;
- API消費者和憑證管理;
- 插件機制;
- 分佈式數據存儲;
- 命令行工具CLI。
MicroGateway
項目地址:
https://github.com/strongloop/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的文章:https://spencergibb.netlify.com/preso/detroit-cf-api-gateway-2017-03/。
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代碼,大部分可以在這裡找到:
https://github.com/ 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:
https://www.sczyh30.com/tags/Vert-x/。

圖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服務的重要等級和客戶的分類,進一步細化和實時控制網關策略,最大限度地保障核心業務和客戶的使用。
從監控圖表可以看到,優化之後的效果非常明顯,系統穩定,連接數平穩。