開源網關【轉】

轉自https://gitbook.cn/books/5bbb3d2a61d11c2d996be26b/index.html

百億流量 API 網關設計與實踐

kimmking

向作者提問

秦金衛,現某公司高級技術總監/Apache Dubbo Committer,前阿里架構師/某商業銀行北京研發中心負責人。關注於互聯網電商,金融,支付等系統領域,10多年研發管理和架構經驗,對於中間件、SOA、微服務,以及各種開源技術非常熱衷,活躍於Dubbo,Fastjson,Mule,ActiveMQ等各類開源社區。

查看本場Chat

 

 

本次分享我們從百億流量交易系統 API 網關(API Gateway)的現狀和麪臨問題出發,闡述微服務架構與 API 網關的關係,理順流量網關與業務網關的脈絡,帶來最全面的 API 網關知識與經驗。內容涉及:

第一部分:API 網關概述

  • 分佈式服務架構、微服務架構與 API 網關
  • API 網關的定義與職能、關注點
  • API 網關的分類與技術分析

第二部分:開源網關的分析與調研

  • 常見的開源網關介紹
  • 四大開源網關的對比分析(OpenResty/Kong/Zuul2/SpringCloudGateway 等)
  • 開源網關的技術總結

第三部分:百億流量交易系統 API 網關設計

  • 百億流量 API 網關的現狀和麪臨問題
  • 業務網關的設計與最佳實踐
  • 對API網關的發展展望

第一部分:API 網關概述

計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決。 —— David Wheeler

分佈式服務架構、微服務架構與 API 網關

什麼是 API 網關(API Gateway)

其實網關跟面向服務架構(Service Oriented Architecture,SOA)和微服務架構(MicroServices Architecture,MSA)有很深的淵源。

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

enter image description here

enter image description here

人們基於 SOA 的理念,在綜合前置的基礎上,進一步增加了服務的元數據管理、註冊、中介、編排、治理等功能,逐漸形成了企業服務總線(ESB,Enterprise Service Bus)。

enter image description here(作者參與設計開發的 Primeton ESB 系統)

enter image description here

面向服務架構(SOA)是一種建設企業 IT 生態系統的架構指導思想。SOA 的關注點是服務,服務最基本的業務功能單元,由平臺中立性的接口契約來定義。通過將業務系統服務化,可以將不同模塊解耦,各種異構系統間可以輕鬆實現服務調用、消息交換和資源共享。

不同於以往的孤立業務系統,SOA 強調整個企業 IT 生態環境是一個大的整體。整個 IT 生態中的所有業務服務構成了企業的核心 IT 資源。各系統的業務拆解爲不同粒度和層次的模塊和服務,服務可以組裝到更大的粒度,不同來源的服務可以編排到同一個處理流程,實現非常複雜的集成場景和更加豐富的業務功能。

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

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

分佈式服務架構、微服務架構與 API 網關

而近年來,隨着互聯網技術的飛速發展,爲了解決以 ESB 這種集中式管理的 SOA 方案的種種問題,以 Apache Dubbo(2011 年開源後)與新近出現的 Spring Cloud 爲代表的分佈式技術的出現,給了 SOA 實現的另外一個選擇:去中心化的分佈式服務架構(DSA)。分佈式服務架構技術不再依賴於具體的服務中心容器技術(比如 ESB),而是將服務尋址和調用完全分開,這樣就不需要通過容器作爲服務代理,在運行期實現最搞笑的直連調用。

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

enter image description here

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

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

API 網關的技術趨勢

enter image description here

我們從百度指數趨勢看到,SpringCloud 和 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 > NodeJS/JavaScript > Java > Lua > C/C++ > PHP > Python/Ruby/Perl

API 網關的定義、職能與關注點

API 網關的定義

網關的角色是作爲一個 API 架構,用來保護、增強和控制對於 API 服務的訪問。

The role of a Gateway in an API 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、Dotnet、Python,還是 PHP、ROR、NodeJS 等,只要是支持 REST API,就可以被 API 網關管理起來。

API 網關的職能

enter image description here

一般來說,API 網關有四大職能:

  • 請求接入:作爲所有 API 接口服務請求的接入點,管理所有的接入請求;
  • 業務聚合:作爲所有後端業務服務的聚合點,所有的業務服務都可以在這裏被調用;
  • 中介策略:實現安全、驗證、路由、過濾、流控,緩存等策略,進行一些必要的中介處理;
  • 統一管理:提供配置管理工具,對所有 API 服務的調用生命週期和相應的中介策略進行統一管理。

API 網關的關注點

通過以上的分析可以看出,API 網關不是一個典型的業務系統, 而是一個爲了讓業務系統更專注與業務服務本身,給API服務提供更多附加能力的一箇中間層。

這樣在設計和實現 API 網關時,兩個目標需要考慮:

  1. 開發維護簡單,節約人力成本和維護成本。這要求我們使用非常成熟的簡單可維護的技術體系。
  2. 高性能,節約設備成本,提高系統吞吐能力。這要求我們需要針對 API 網關的特點,進行一些特定的設計和權衡。 當併發量小的時候,這些都不是問題。然後一旦系統的 API 訪問量非常大的時候,這些都會成爲關鍵的問題。

海量併發的 Gateway 最重要的三個關注點:

  1. 保持大規模的 inbound 請求接入能力(長短連接),比如基於 netty 實現。
  2. 最大程度的複用 outbound 的 HTTP 連接能力,比如基於 HttpClient4 的 asynchronizedHttpclient 實現。
  3. 方便靈活地實現安全、驗證、過濾、聚合、限流、監控等各種策略。

API 網關的分類與技術分析

API 網關的分類

如果我們對於上述的目標和關注點進行更深入的思考,就會發現一個很重要的問題:所有需要考慮的問題和功能可以分爲兩類。

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

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

這樣,隨着互聯網的複雜業務系統的發展,這兩類功能集合逐漸形成了現在常見的兩種網關係統:流量網關和業務網關。

enter image description here

流量網關與 WAF

我們定義全局性的、跟具體的後端業務系統和服務完全無關的策略網關,即爲流量網關。這樣流量網關關注於全局流量的穩定與安全,具體比如防止各類 SQL 注入,黑白名單控制,接入請求到業務系統的 Loadbalance 等,通常有如下的一些通用性功能:

  • 全局性流控
  • 日誌統計
  • 防止 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 開源實現

以上 WAF 的內容主要參考如下兩個項目:

流量網關的開源實例,還可以參考著名的開源項目 Kong(基於 OpenResty)。

業務網關

我們定義針對具體的後端業務系統,或者是服務和業務有一定關聯性的策略網關,即爲業務網關。比如針對某個系統、某個服務或者某個用戶分類的流控策略,針對某一類服務的緩存策略,針對某個具體系統的權限驗證方式,針對某些用戶條件判斷的請求過濾,針對具體幾個相關API的數據聚合封裝等等。

業務網關一般部署在流量網關之後,業務系統之前,比流量網關更靠近系統。我們大部分情況下說的 API 網關,狹義上指的是業務網關。並且如果系統的規模不大,我們也會將兩者合二爲一,使用一個網關來處理所有的工作。具體的業務網關設計實現,將在下面的篇章詳細介紹。

第二部分:開源網關的分析與調研

常見的開源網關介紹

enter image description here(開源網關技術圖譜)

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

  • Nginx+lua:Open Resty、Kong、Orange、Abtesting gateway 等
  • Java:Zuul/Zuul2、Spring Cloud Gateway、Kaazing KWG、gravitee、Dromara soul 等
  • Go:Janus、fagongzi、Grpc-gateway
  • Dotnet:Ocelot
  • NodeJS:Express Gateway、Micro Gateway

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

  • OpenResty
  • Kong
  • Zuul/Zuul2
  • Spring Cloud Gateway

Nginx+Lua

Open Resty

項目地址:http://openresty.org/

OpenResty® 是一個基於 Nginx 與 Lua 的高性能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用於方便地搭建能夠處理超高併發、擴展性極高的動態 Web 應用、Web 服務和動態網關。

OpenResty® 通過匯聚各種設計精良的 Nginx 模塊(主要由 OpenResty 團隊自主開發),從而將 Nginx 有效地變成一個強大的通用 Web 應用平臺。這樣,Web 開發人員和系統工程師可以使用 Lua 腳本語言調動 Nginx 支持的各種 C 以及 Lua 模塊,快速構造出足以勝任 10K 乃至 1000K 以上單機併發連接的高性能 Web 應用系統。

OpenResty® 的目標是讓你的 Web 服務直接跑在 Nginx 服務內部,充分利用 Nginx 的非阻塞 I/O 模型,不僅僅對 HTTP 客戶端請求,甚至於對遠程後端諸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都進行一致的高性能響應。

以上介紹來自於 OpenResty 網站中文版。簡單的說,OpenResty 基於 Nginx,集成了 Lua 語言和 Lua 的各種工具庫,可用的第三方模塊,這樣我們就在 Nginx 既有的高效 HTTP 處理的基礎上,同時獲得了 Lua 提供的動態擴展能力。因此,我們可以做出各種符合我們需要的網關策略的 Lua 腳本,以其爲基礎實現我們的網關係統。

Kong

項目地址:

Kong 基於 OpenResty,是一個雲原生、快速、可擴展、分佈式的微服務抽象層(Microservice Abstraction Layer),也叫 API 網關(API Gateway),在 Service Mesh 裏也叫 API 中間件(API Middleware)。

Kong 開源於 2015 年,核心價值在於高性能和擴展性。從全球 5000 強的組織統計數據來看,Kong 是現在依然在維護的,在生產環境使用最廣泛的 API 網關。

Kong 宣稱自己是世界上最流行的開源微服務 API 網關(The World’s Most Popular Open Source Microservice API Gateway)。

核心優勢:

  • 可擴展:可以方便的通過添加節點水平擴展,這意味着可以在很低的延遲下支持很大的系統負載。
  • 模塊化:可以通過添加新的插件來擴展 Kong 的能力,這些插件可以通過 RESTful Admin API 來安裝和配置。
  • 在任何基礎架構上運行:Kong 可以在任何地方都能運行,比如在雲或混合環境中部署 Kong,單個或全球的數據中心。

enter image description here

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 複用、熔斷降級、一鍵截流和性能統計等功能。

Java

Zuul/Zuul2

項目地址:https://github.com/Netflix/zuul

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

Zuul 的內部原理可以簡單看做是很多不同功能 filter 的集合(PS:作爲對比,ESB 也可以簡單被看做是管道(channel)和過濾器(filter)的集合),這些 filter 可以使用 Groovy 或其他基於 JVM 的腳本編寫(當然 Java 也可以編寫),放置在指定的位置,然後可以被 Zuul Server 輪詢發現變動後動態加載並實時生效。

Zuul 目前有兩個大的版本,1.x 和 2.x,這兩個版本差別很大。

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

在 Zuul 1.x 裏,filter 的種類和處理流程可以參見下圖,最主要的就是 pre、routing、post 這三種過濾器,分別作用於調用業務服務 API 之前的請求處理、直接響應、調用業務服務 API 之後的響應處理。

enter image description here(Zuul 1.x 示意圖)

Zuul 2.x 最大的改進就是基於 Netty Server 實現了異步 IO 來接入請求,同時基於 Netty Client 實現了到後端業務服務 API 的請求。這樣就可以實現更高的性能、更低的延遲。此外也調整了 filter 類型,將原來的三個核心 filter 顯式命名爲:Inbound Filter、Endpoint Filter 和 Outbound Filter。

enter image description here(Zuul 2.x 示意圖)

Zuul 2.x 核心功能:

  • Service Discovery
  • Load Balancing
  • Connection Pooling
  • Status Categories
  • Retries
  • Request Passport
  • Request Attempts
  • Origin Concurrency Protection
  • HTTP/2
  • Mutual TLS
  • Proxy Protocol
  • GZip
  • WebSockets

Spring Cloud 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 實現異步 IO,從而實現了一個簡單、比 Zuul 1.x 更高效的、與 Spring Cloud 緊密配合的 API 網關。

Spring Cloud Gateway 裏明確的區分了 Router 和 Filter,並且一個很大的特點是內置了非常多的開箱即用功能,並且都可以通過 SpringBoot 配置或者手工編碼鏈式調用來使用。

比如內置了 10 種 Router,使得我們可以直接配置一下就可以隨心所欲的根據 Header、或者 Path、或者 Host、或者 Query 來做路由。

比如區分了一般的 Filter 和全局 Filter,內置了 20 種 Filter 和 9 種全局 Filter,也都可以直接用。當然自定義 Filter 也非常方便。

核心特性:

  • Able to match routes on any request attribute.
  • Predicates and filters are specific to routes.
  • Hystrix Circuit Breaker integration.
  • Spring Cloud DiscoveryClient integration
  • Easy to write Predicates and Filters
  • Request Rate Limiting
  • Path Rewriting

gravitee gateway

項目地址:

Kaazing 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

Go

fagongzi

項目地址:

https://github.com/fagongzi/gateway

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

功能特性:

  • 流量控制
  • 熔斷
  • 負載均衡
  • 服務發現
  • 插件機制
  • 路由(分流,複製流量)
  • API 聚合
  • API 參數校驗
  • API 訪問控制(黑白名單)
  • API 默認返回值
  • API 定製返回值
  • API 結果 Cache
  • JWT Authorization
  • API Metric 導入 Prometheus
  • API 失敗重試
  • 後端 server 的健康檢查
  • 開放管理 API(GRPC、Restful)
  • 支持 Websocket 協議

Janus

項目地址:

https://github.com/hellofresh/janus

Janus 是一個輕量級的 API Gateway 和管理平臺,它能幫你實現控制誰,什麼時候,如何訪問這些 REST API,同時它也記錄了所有的訪問交互細節和錯誤。

使用 Go 實現 API 網關的一個好處在於,一般只需要一個單獨的二進制文件即可運行,沒有複雜的依賴關係(No dependency hell)。

功能特性:

  • 熱加載配置,不需要重啓網關進程
  • HTTP 連接的優雅關閉
  • 支持 OpenTracing,從而可以進行分佈式跟蹤
  • 支持 HTTP/2
  • 可以針對每一個 API 實現斷路器
  • 重試機制
  • 流控,可以針對每一個用戶或者 key
  • CORS 過濾,可以針對具體的 API
  • 多種開箱即用的驗證協議支持,比如 JWT、OAuth2.0 和 Basic Auth
  • docker image 支持

Dotnet

Ocelot

項目地址:

https://github.com/ThreeMammals/Ocelot

核心特性:

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

NodeJS

Express Gateway

項目地址:

Express Gateway 是一個基於 NodeJS 開發,Express 和 Express 中間件實現的 REST API 網關。

核心特性:

  • 動態中心化配置
  • API 消費者和憑證管理
  • 插件機制
  • 分佈式數據存儲
  • 命令行工具 CLI

microgateway

項目地址:

StrongLoop 是 IBM 的一個子公司,Microgateway 網關基於 Node.js/Express 和 Nginx 構建,作爲 IBM API Connect,同時也是 IBM 雲生態的一部分。

Microgateway 是一個聚焦於開發者,可擴展的網關框架,它可以增強我們對微服務和 API 的訪問能力。

核心特性:

  • 安全和控制,基於 Swagger(OpenAPI) 規範
  • 內置了多種網關策略,API Key 驗證、流控、OAuth2.0、JavaScript 腳本支持
  • 使用 Swagger 擴展(API Assembly)實現網關策略(安全、路由、集成等)
  • 方便地自定義網關策略

此外,Microgateway 還有幾個特性:

  • 通過集成 Swagger,實現基於 Swagger API 定義的驗證能力
  • 使用 datastore 來保持需要處理的 API 數據模型
  • 使用一個流式引擎來處理多種策略,使得 API 設計者可以更好的控制 API 的生命週期

核心架構如下圖所示:

enter image description here

四大開源網關的對比分析(OpenResty/Kong/Zuul2/SpringCloudGateway 等)

OpenResty/Kong/Zuul2/SpringCloudGateway 重要特性對比

網關 限流 鑑權 監控 易用性 可維護性 成熟度
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庫 相對成熟,用戶問題彙總,社區,插件開源

以限流功能爲例:

  • Spring Cloud Gateway 目前提供了基於 Redis 的 Ratelimiter 實現,使用的算法是令牌桶算法,通過 yml 文件進行配置;
  • Zuul2 可以通過配置文件配置集羣限流和單服務器限流亦可通過 filter 實現限流擴展;
  • OpenResty 可以使用 resty.limit.count、resty.limit.conn、resty.limit.req 來實現限流功能可實現漏桶或令牌通算法;
  • Kong 擁有基礎限流組件,可在基礎組件源代碼基礎上進行 lua 開發。

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

https://spencergibb.netlify.com/preso/detroit-cf-api-gateway-2017-03/

OpenResty/Kong/Zuul2/SpringCloudGateway 性能測試對比

分別使用 3 臺 4Core16G 內存的機器,作爲 API 服務提供者、Gateway、壓力機,使用 wrk 作爲性能測試工具,對 OpenResty/Kong/Zuul2/SpringCloudGateway 進行簡單小報文的情況進行性能測試。

enter image description here(Spring Cloud Gateway、Zuul2、OpenResty、Kong 的性能對比)

上圖中 y 軸座標是 QPS,x 軸是一個 Gateway 的數據,每根線是一個場景下的不同網關數據,測試結論如下:

  • 實測情況是性能 SCG~Zuul2 << OpenResty ~< Kong << Direct(直連);
  • Spring Cloud Gateway、Zuul2 的性能差不多,大概是直連的40%;
  • OpenResty、Kong 差不多,大概是直連的 60-70%;
  • 大併發下,例如模擬 200 併發用戶、1000 併發用戶時,Zuul2 會有很大概率返回出錯。

開源網關的技術總結

開源網關的測試分析

脫離場景談性能,都是耍流氓。性能就像溫度,不同的場合下標準是不一樣的。同樣是 18 攝氏度,老人覺得冷,小孩覺得很合適,企鵝覺得熱,冰箱裏的蔬菜可能要壞了。

同樣基準條件下,不同的參數和軟件,相對而言的橫向比較,才有價值。比如同樣的機器(比如 16G 內存/4Core),同樣的 server(用 Spring Boot,配置路徑 api/hello 返回一個 helloworld),同樣的壓測方式和工具(比如用 WRK,10 線程,20 併發連接),我們測試直接訪問 server 得到的極限 QPS(QPS-Direct,29K);和配置了一個 Spring Cloud Gateway 做網關訪問的極限 QPS(QPS-SCG,11K)、同樣方式配置一個 Zuul2 做網關壓測得到的極限 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/Zuul2 對於 Java 技術棧來說比較方便,可以依賴業務系統的一些 common jar。Lua 不方便,不光是語言的問題,更是複用基礎設施的問題。另外,對於網關係統來說,性能不是差一個數量級,問題不大,多加 2 臺機器就可以搞定。

目前測試的總結來看,如果服務都是 2ms 級別,直連的性能假如是 100,Kong 可以到 60,OpenResty 是 50,Zuul2 和 Spring Cloud Gateway 是 35,如果服務本身的 latency 大一點,這些個差距會逐步縮小。

目前來看 Zuul2 的坑還是比較多的:

  1. 不成熟,沒文檔,剛出不久,還沒有太多的實際應用案例
  2. 高併發時出錯率較高,1000 併發時我們的測試場景近 50% 的出錯

所以簡單使用或者輕度定製業務網關係統,目前比較建議使用 Spring Cloud Gateway 作爲基礎骨架。

各類網關的 demo 與測試

以上測試用到的模擬服務和網關 demo 代碼,大部分可以在這裏找到:

https://github.com/kimmking/spring-cloud-gateway-demo

這裏也簡單模擬了一個 NodeJS 做的 Gateway,加了 keep-alive 和 pool,demo 的性能測試結果大概是直連的 1/9,也就是 Spring Cloud Gateway 或 Zuul2 的 1/4 左右。

第三部分:百億流量交易系統 API 網關設計

百億流量交易系統 API 網關的現狀和麪臨問題

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

enter image description here

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

在這個情況下,API 網關設計的一個重要目標就是:如何藉助 API 網關爲各類客戶提供精準、專業、個性化的服務,保障客戶實時的獲得業務系統的數據和業務能力。

網關係統與其他系統的關係

我們的業務裏,API 網關係統與其他系統的關係大致如下圖所示:

enter image description here

網關係統典型的應用場景

我們的 API 網關係統爲 Web 端、移動 APP 端客戶提供服務,同時也爲大量 API 客戶提供 API 調用服務,同時支持 REST API 和 WebSocket 協議。

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

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

enter image description here

enter image description here

交易系統 API 的特點

作爲一個全球性的交易系統,API 的特點總結如下:

  • 訪問非常集中:最核心的一組 API,佔據了訪問量的一半以上
  • 訪問非常頻繁:QPS 非常高,日均訪問量非常大
  • 數據格式固定:交易系統處理的數據格式非常固定
  • 報文數據量小:每次請求傳輸的數據一般不超過 10K
  • 用戶全世界分佈:客戶分佈在全世界的各個國家
  • 分內部調用和外部調用:除了 API 客戶直接調用的 API,其他的 API 都是由內部其他系統調用的
  • 7x24 小時不間斷服務:系統需要提供高可用、不間斷的服務能力,以滿足不同時區客戶的交易和自動化策略交易
  • 外部用戶有一定技術能力:外部 API 客戶,一般是自己集成我們的 API,實現自己的交易系統

交易系統 API 網關面臨的問題

問題 1:流量的不斷增加

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

問題 2:網關係統越來越複雜

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

同時技術債務太多,系統裏硬編碼實現了全局性網關策略以及很多業務規則,導致維護成本較大。

問題 3:API 網關管理比較困難

海量併發下 API 的監控指標設計和數據的收集也是一個不小的問題。7x24 小時運行的技術支持也導致維護成本較高。

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

使用短連接還是長連接,REST API 還是 WebSocket?

業務渠道較多(多個不同產品線的 Web、App、API 等形成十幾個不同的渠道),導致用戶的使用行爲難以控制。

業務網關的設計與最佳實踐

API 網關 1.0

我們的 API 網關 1.0 版本是多年前開發的,是直接使用 OpenResty 定製的,全局的安全測試、流量的路由轉發策略、針對不同級別的限流等都是直接用 Lua 腳本實現。

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

API 網關 2.0

在區分了流量網關和業務網關以後,2017 年開始實現了流量網關和業務網關的分離,流量網關繼續使用 OpenResty 定製,只保留少量全局性,不經常改動的配置功能和對應的 Lua 腳本。

業務網關使用 Vert.x實現的 Java 系統,部署在流量網關和後端業務服務系統之間,利用 Vert.x 的反應式編程能力和異步非阻塞 IO 能力、分佈式部署的擴展能力,這樣就初步解決了問題 1 和問題 2。

enter image description here

Vert.x 是一個基於事件驅動和異步非阻塞 IO、運行於 JVM 上的框架,如下圖所示。在 Vert.x 裏,Verticle 是最基礎的開發和部署單元,不同的 Vert.x 可以通過 Event Bus 傳遞數據,進而方便的實現高併發性能的網絡程序。關於 Vert.x 原理的分析可以參考阿里宿何的 blog:https://www.sczyh30.com/tags/Vert-x/

enter image description here

Vert.x 同時也很好的支持 Websocket 協議,所以可以方便的實現支持 REST API 和 Websocket、完全異步的網關係統。

enter image description here

一個高性能的 API 網關係統,緩存是必不可少的部分。無論是分發冷熱數據,降低對業務系統的壓力,還是作爲中間數據源,爲服務聚合提供高效可複用的業務數據,都發揮了巨大作用。而一個優秀、高效的緩存系統,也必須是需要針對所承載的業務數據特點,進行特定設計和實現的。

enter image description here

API 網關的日常監控

我們使用多種工具對 API 進行監控和管理,全鏈路訪問跟蹤、連接數統計分析、全世界重要國家和城市的波測訪問統計。網關技術團隊每時每刻都關注着數據的變化趨勢。各個業務系統研發團隊,每天安排專人關注自己系統的 API 性能,推進性能問題解決和持續優化。這就初步解決了問題 3。

enter image description here

enter image description here

enter image description here

enter image description here

推薦外部客戶使用 Websocket

由於外部客戶需要自己通過 API 網關調用 API 服務來集成業務服務能力到自己的系統,各個客戶的技術能力和系統處理能力有較大差異,使用行爲也各有不同。對於不斷髮展變動的交易業務數據,客戶調用 API 頻率太低則會影響數據實時性,調用頻率太高則可能會浪費雙方的系統資源。同時利用 Websocket 的消息推送特點,我們可以在網關係統控制客戶接受消息的頻率、單個用戶的連接數量等,隨時根據業務系統的情況動態進行策略調整。綜合考慮,Websocket 是一個比 REST API 更加實時可靠,更加易於管理的方式。通過逐步協助和鼓勵客戶使用 Websocket 協議上,基本解決了問題 4。

API 網關的性能優化

API 網關係統作爲 API 的統一接入點,爲了給用戶提供最優質的用戶體驗,必須長期做性能優化工作。

不僅 API 網關自己做優化,同時可以根據監控情況,時刻發現各業務系統的 API 服務能力,以此爲出發點,推動各個業務系統不斷優化 API 性能。

在此舉一個具體的例子,某個網關係統發現連接經常劇烈抖動(如下圖所示),嚴重影響系統的穩定性、浪費系統資源,經過排除發現:

  1. 有爬蟲 IP 不斷爬取我們的交易數據,且這些 IP 所在網段都沒有在平臺產生任何實際交易,最高單爬蟲IP的每日新建連接近 100 萬次,平均每秒 10 幾次;
  2. 有部分 API 客戶的程序存在 bug,且處理速度有限,不斷的斷開並重新連接,嘗試重新對 API 數據進行處理,嚴重影響了客戶的用戶體驗。

針對如上分析,我們採取了幾個處理方式:

  1. 對於每天認定的爬蟲 IP,加入黑名單,直接在流量網關限制其訪問我們的 API 網關;
  2. 對於存在 bug 的 API 客戶,協助對方進行問題定位和bug修復,增強客戶使用信心;
  3. 對於處理速度和技術能力有限的客戶,基於定製的 Websocket 服務,使用滑動時間窗口算法,在業務數據變化非常大時,對分發的消息進行批量優化;
  4. 對於未登錄和識別身份的 API 調用,流量網關實現全局的流控策略,增加緩存時間和限制調用次數,保障系統穩定;
  5. 業務網關則根據 API 服務的重要等級和客戶的分類,進一步細化和實時控制網關策略,最大程度保障核心業務和客戶的使用。

優化前:

enter image description here

優化後:

enter image description here

對 API 網關的發展展望

enter image description here

  1. 現有的 API Gateway 是以 Vert.x 爲基礎、結合業務自研的網關係統 Gateway 2.0。
  2. 目前計劃年底前基於 Spring Cloud 和 Spring Cloud Gateway 實現新一代微服務架構的網關係統 Gateway 3.0。
  3. 計劃明年上半年將整合了流量網關和業務網關、並增加了很多開箱即用功能組件的微服務架構網關,作爲 Apollo Gateway 1.0 開源。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章