微服務網關選型:5 種主流 API 網關,哪個最香!
微服務近幾年非常火,圍繞微服務的技術生態也比較多,比如微服務網關、Docker、Kubernetes 等。
我是於 2019 年開始接觸微服務網關,當時和公司的一位同事一起開發,由於技術能力有限,我只負責網關後臺,後續微服務網關的迭代,我其實沒有參與,不過後來抽空看了微服務網關前臺的代碼,所以對這套微服務網關的實現原理算是基本掌握。
最近在寫技術棧相關的文章,剛好寫到微服務網關,就把之前學習的知識進行簡單總結,同時也把市面上常用的微服務網關進行梳理,一方面便於後續技術選型,另一方面也算是給自己一個交代。下面是文章目錄:
API 網關基礎
什麼是 API 網關
API 網關是一個服務器,是系統的唯一入口。 從面向對象設計的角度看,它與外觀模式類似。
API 網關封裝了系統內部架構,爲每個客戶端提供一個定製的 API。它可能還具有其它職責,如身份驗證、監控、負載均衡、緩存、協議轉換、限流熔斷、靜態響應處理。
API 網關方式的核心要點是,所有的客戶端和消費端都通過統一的網關接入微服務,在網關層處理所有的非業務功能。通常,網關也是提供 REST/HTTP 的訪問 API。
網關的主要功能
微服務網關作爲微服務後端服務的統一入口,它可以統籌管理後端服務,主要分爲數據平面和控制平面:
-
數據平面主要功能是接入用戶的 HTTP 請求和微服務被拆分後的聚合。使用微服務網關統一對外暴露後端服務的 API 和契約,路由和過濾功能正是網關的核心能力模塊。另外,微服務網關可以實現攔截機制和專注跨橫切面的功能,包括協議轉換、安全認證、熔斷限流、灰度發佈、日誌管理、流量監控等。
-
控制平面主要功能是對後端服務做統一的管控和配置管理。例如,可以控制網關的彈性伸縮;可以統一下發配置;可以對網關服務添加標籤;可以在微服務網關上通過配置 Swagger 功能統一將後端服務的 API 契約暴露給使用方,完成文檔服務,提高工作效率和降低溝通成本。
-
路由功能:路由是微服務網關的核心能力。通過路由功能微服務網關可以將請求轉發到目標微服務。在微服務架構中,網關可以結合註冊中心的動態服務發現,實現對後端服務的發現,調用方只需要知道網關對外暴露的服務 API 就可以透明地訪問後端微服務。
-
負載均衡:API 網關結合負載均衡技術,利用 Eureka 或者 Consul 等服務發現工具,通過輪詢、指定權重、IP 地址哈希等機制實現下游服務的負載均衡。
-
統一鑑權:一般而言,無論對內網還是外網的接口都需要做用戶身份認證,而用戶認證在一些規模較大的系統中都會採用統一的單點登錄(Single Sign On)系統,如果每個微服務都要對接單點登錄系統,那麼顯然比較浪費資源且開發效率低。API 網關是統一管理安全性的絕佳場所,可以將認證的部分抽取到網關層,微服務系統無須關注認證的邏輯,只關注自身業務即可。
-
協議轉換:API 網關的一大作用在於構建異構系統,API 網關作爲單一入口,通過協議轉換整合後臺基於 REST、AMQP、Dubbo 等不同風格和實現技術的微服務,面向 Web Mobile、開放平臺等特定客戶端提供統一服務。
-
指標監控:網關可以統計後端服務的請求次數,並且可以實時地更新當前的流量健康狀態,可以對 URL 粒度的服務進行延遲統計,也可以使用 Hystrix Dashboard 查看後端服務的流量狀態及是否有熔斷髮生。
-
限流熔斷:在某些場景下需要控制客戶端的訪問次數和訪問頻率,一些高併發系統有時還會有限流的需求。在網關上可以配置一個閾值,當請求數超過閾值時就直接返回錯誤而不繼續訪問後臺服務。當出現流量洪峯或者後端服務出現延遲或故障時,網關能夠主動進行熔斷,保護後端服務,並保持前端用戶體驗良好。
-
黑白名單:微服務網關可以使用系統黑名單,過濾 HTTP 請求特徵,攔截異常客戶端的請求,例如 DDoS 攻擊等侵蝕帶寬或資源迫使服務中斷等行爲,可以在網關層面進行攔截過濾。比較常見的攔截策略是根據 IP 地址增加黑名單。在存在鑑權管理的路由服務中可以通過設置白名單跳過鑑權管理而直接訪問後端服務資源。
-
灰度發佈:微服務網關可以根據 HTTP 請求中的特殊標記和後端服務列表元數據標識進行流量控制,實現在用戶無感知的情況下完成灰度發佈。
-
流量染色:和灰度發佈的原理相似,網關可以根據 HTTP 請求的 Host、Head、Agent 等標識對請求進行染色,有了網關的流量染色功能,我們可以對服務後續的調用鏈路進行跟蹤,對服務延遲及服務運行狀況進行進一步的鏈路分析。
-
文檔中心:網關結合 Swagger,可以將後端的微服務暴露給網關,網關作爲統一的入口給接口的使用方提供查看後端服務的 API 規範,不需要知道每一個後端微服務的 Swagger 地址,這樣網關起到了對後端 API 聚合的效果。
-
日誌審計:微服務網關可以作爲統一的日誌記錄和收集器,對服務 URL 粒度的日誌請求信息和響應信息進行攔截。
API 網關選型
常用 API 網關
先簡單看一下市面上常用的 API 網關:
Nginx
Nginx 是一個高性能的 HTTP 和反向代理服務器。Nginx 一方面可以做反向代理,另外一方面可以做靜態資源服務器,接口使用 Lua 動態語言可以完成靈活的定製功能。
Nginx 在啓動後,會有一個 Master 進程和多個 Worker 進程,Master 進程和 Worker 進程之間是通過進程間通信進行交互的,如圖所示。Worker 工作進程的阻塞點是在像 select()、epoll_wait() 等這樣的 I/O 多路複用函數調用處,以等待發生數據可讀 / 寫事件。Nginx 採用了異步非阻塞的方式來處理請求,也就是說,Nginx 是可以同時處理成千上萬個請求的。
Zuul
Zuul 是 Netflix 開源的一個 API 網關組件,它可以和 Eureka、Ribbon、Hystrix 等組件配合使用。社區活躍,融合於 SpringCloud 完整生態,是構建微服務體系前置網關服務的最佳選型之一。
Zuul 的核心是一系列的過濾器,這些過濾器可以完成以下功能:
-
統一鑑權 + 動態路由 + 負載均衡 + 壓力測試
-
審查與監控:與邊緣位置追蹤有意義的數據和統計結果,從而帶來精確的生產視圖。
-
多區域彈性:跨越 AWS Region 進行請求路由,旨在實現 ELB(Elastic Load Balancing,彈性負載均衡)使用的多樣化,以及讓系統的邊緣更貼近系統的使用者。
Zuul 目前有兩個大的版本:Zuul1 和 Zuul2
Zuul1 是基於 Servlet 框架構建,如圖所示,採用的是阻塞和多線程方式,即一個線程處理一次連接請求,這種方式在內部延遲嚴重、設備故障較多情況下會引起存活的連接增多和線程增加的情況發生。
Netflix 發佈的 Zuul2 有重大的更新,它運行在異步和無阻塞框架上,每個 CPU 核一個線程,處理所有的請求和響應,請求和響應的生命週期是通過事件和回調來處理的,這種方式減少了線程數量,因此開銷較小。
Spring Cloud GateWay
Spring Cloud Gateway 是 Spring Cloud 的一個全新的 API 網關項目,目的是爲了替換掉 Zuul1,它基於 Spring5.0 + SpringBoot2.0 + WebFlux(基於⾼性能的 Reactor 模式響應式通信框架 Netty,異步⾮阻塞模型)等技術開發,性能⾼於 Zuul,官⽅測試,Spring Cloud GateWay 是 Zuul 的 1.6 倍,旨在爲微服務架構提供⼀種簡單有效的統⼀的 API 路由管理⽅式。
Spring Cloud Gateway 可以與 Spring Cloud Discovery Client(如 Eureka)、Ribbon、Hystrix 等組件配合使用,實現路由轉發、負載均衡、熔斷、鑑權、路徑重寫、⽇志監控等,並且 Gateway 還內置了限流過濾器,實現了限流的功能。
Kong
Kong 是一款基於 OpenResty(Nginx + Lua 模塊)編寫的高可用、易擴展的,由 Mashape 公司開源的 API Gateway 項目。Kong 是基於 NGINX 和 Apache Cassandra 或 PostgreSQL 構建的,能提供易於使用的 RESTful API 來操作和配置 API 管理系統,所以它可以水平擴展多個 Kong 服務器,通過前置的負載均衡配置把請求均勻地分發到各個 Server,來應對大批量的網絡請求。
Kong 主要有三個組件:
-
Kong Server :基於 Nginx 的服務器,用來接收 API 請求。
-
Apache Cassandra/PostgreSQL :用來存儲操作數據。
-
Kong dashboard:官方推薦 UI 管理工具,也可以使用 restfull 方式管理 admin api。
Kong 採用插件機制進行功能定製,插件集(可以是 0 或 N 個)在 API 請求響應循環的生命週期中被執行。插件使用 Lua 編寫,目前已有幾個基礎功能:HTTP 基本認證、密鑰認證、CORS(Cross-Origin Resource Sharing,跨域資源共享)、TCP、UDP、文件日誌、API 請求限流、請求轉發以及 Nginx 監控。
Kong 網關具有以下的特性:
-
可擴展性: 通過簡單地添加更多的服務器,可以輕鬆地進行橫向擴展,這意味着您的平臺可以在一個較低負載的情況下處理任何請求;
-
模塊化: 可以通過添加新的插件進行擴展,這些插件可以通過 RESTful Admin API 輕鬆配置;
-
在任何基礎架構上運行: Kong 網關可以在任何地方都能運行。您可以在雲或內部網絡環境中部署 Kong,包括單個或多個數據中心設置,以及 public,private 或 invite-only APIs。
Traefik
Træfɪk 是一個爲了讓部署微服務更加便捷而誕生的現代 HTTP 反向代理、負載均衡工具。它支持多種後臺 (Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd, Zookeeper, BoltDB, Rest API, file…) 來自動化、動態的應用它的配置文件設置。
重要特性:
-
它非常快,無需安裝其他依賴,通過 Go 語言編寫的單一可執行文件;
-
多種後臺支持:Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd;
-
支持支持 Rest API、Websocket、HTTP/2、Docker 鏡像;
-
監聽後臺變化進而自動化應用新的配置文件設置;
-
配置文件熱更新,無需重啓進程;
-
後端斷路器、負載均衡、容錯機制;
-
清爽的前端頁面,可監控服務指標。
關於 Traefik 的更多內容,可以查看官網:https://traefik.cn/
API 網關對比
上面是網關對比截圖,偷個懶,大家主要關注 Kong、Traefik 和 Zuul 即可:
-
從開源社區活躍度來看,無疑是 Kong 和 Traefik 較好;
-
從成熟度來看,較好的是 Kong、Tyk、Traefik;
-
從性能來看,Kong 要比其他幾個領先一些;
-
從架構優勢的擴展性來看,Kong、Tyk 有豐富的插件,Ambassador 也有插件但不多,而 Zuul 是完全需要自研,但 Zuul 由於與 Spring Cloud 深度集成,使用度也很高,近年來 Istio 服務網格的流行,Ambassador 因爲能夠和 Istio 無縫集成也是相當大的優勢。
下面是其它網友的思考結論,可供參考:
-
性能:Nginx+Lua 形式必然是高於 Java 語言實現的網關的,Java 技術棧裏面 Zuul1.0 是基於 Servlet 實現的,剩下都是基於 webflux 實現,性能是高於基於 Servlet 實現的。在性能方面我覺得選擇網關可能不算那麼重要,多加幾臺機器就可以搞定。
-
可維護性和擴展性:Nginx+Lua 這個組合掌握的人不算多,如果團隊有大神,大佬們就隨意了,當沒看到這段話,對於一般團隊來說的話,選擇自己團隊擅長的語言更重要。Java 技術棧下的 3 種網關,對於 Zuul 和 Spring Cloud Gateway 需要或多或少要搞一些集成和配置頁面來維護,但是對於 Soul 我就無腦看看文章,需要哪個搬哪個好了,尤其是可以無腦對接 Dubbo 美滋滋,此外 Soul2.0 以後版本可以擺脫 ZK,在我心裏再無詬病,我就喜歡無腦操作。
-
高可用:對於網關高可用基本都是統一的策略都是採用多機器部署的方式,前面掛一個負載,對於而外需要用的一些組件大家注意一下。
基於 Traefik 自研的微服務網關
這個是我司自研的微服務網關,基於 Traefik 進行開發,下面從技術選型、網關框架、網關後臺、協議轉換進行講解,絕對乾貨!
技術棧選型
-
Traefik:一款開源的反向代理與負載均衡工具,它最大的優點是能夠與常見的微服務系統直接整合,可以實現自動化動態配置。traefik 較爲輕量,非常易於使用和設置,性能比較好,已在全球範圍內用於生產環境。
-
Etcd:一個 Go 言編寫的分佈式、高可用的一致性鍵值存儲系統,用於提供可靠的分佈式鍵值存儲、配置共享和服務發現等功能。(更多內容可以查看文章 肝了一個月的 ETCD,從 Raft 原理到實踐 )
-
Go:併發能力強,性能媲美 C,處理能力是 PHP 的 4 倍,效率高,語法簡單,易上手,開發效率接近 PHP。
網關框架
整個網關框架分爲 3 塊:
-
網關後臺(hal-fe 和 hal-admin):用於應用、服務和插件的配置,然後將配置信息發佈到 ETCD;
-
Traefik:讀取 ETCD 配置,根據配置信息對請求進行路由分發,如果需要鑑權,會直接通過 hal-agent 模塊進行統一鑑權。鑑權完畢後,如果是 Http 請求,直接打到下游服務,如果是 Grpc 和 Thrift 協議,會通過 hal-proxy 模塊進行協議轉換。
-
協議轉換模塊:讀取 ETCD 配置,對 Traefik 分發過來的請求,進行 Grpc 和 Thrift 協議轉換(更多內容可以查看文章 RPC 框架:從原理到選型,一文帶你搞懂 RPC),並通過服務發現機制,獲取服務下游機器,並通過負載均衡,將轉換後的數據打到下游服務機器。
網關後臺
主要由 3 大模塊組成:
-
應用:主要包括應用名、域名、路徑前綴、所屬組、狀態等,比如印度海外商城、印度社區;
-
服務:主要包括服務名、註冊方式、協議類型、所屬組、狀態等,比如評論服務、地址服務、搜索服務。
-
插件:主要包括插件名稱、插件類型、插件屬性配置等,比如路徑前綴替換插件、鑑權插件。
一個應用只能綁定一個服務,但是可以綁定多個插件。 通過後臺完成網關配置後,將這些配置信息生成 Config 文件,發佈到 ETCD 中,Config 文件需要遵循嚴格的數據格式,比如 Traefix 配置需要遵循官方的文件配置格式,才能被 Traefik 識別。
協議轉換模塊
hal-proxy 模塊是整個微服務網關最複雜,也是技術含量最高的模塊,所以給大家詳細講解一下。
問題引入
在講這個模塊前,我們先看下面幾個問題:
-
當請求從上游的 trafik 過來時,需要知道訪問下游的機器 IP 和端口,才能將請求發送給下游,這些機器如何獲取呢?
-
有了機器後,我們需要和下游機器建立連接,如果連接用一次就直接釋放,肯定對服務會造成很大的壓力,這就需要引入 Client 緩存池,那這個 Client 緩存池我們又該如何實現呢?
-
最後就是需要對協議進行轉換,因爲不同的下游服務,支持的協議類型是不一樣的,這個網關又是如何動態支持的呢?
實現原理
我們還是先看一下 hal-proxy 內部有哪些模塊,首先是 Resolver 模塊,這個模塊的是什麼作用呢?這裏我簡單介紹一下,目前公司內部通過服務獲取到機器列表的方式有多種,比如 MIS 平臺、服務樹等,也就是有的是通過平臺配置的,有的是直接掛在服務樹下,無論哪種方式,我們都通過服務名,通過一定的方式,找到該服務下面所有的主機。
所以 Resolver 模塊的作用,其實就是通過服務名,找到該服務下的所有機器的 IP 和服務端口,然後持久化到內存中,並定時更新。
協議模塊就是支持不同的協議轉換,每個協議類型的轉換,都需要單獨實現,這些協議轉換,無非就是先通過機器 IP 和端口初始化 Client,然後再將數據進行轉換後,直接發送到下游的機器。
最後就是連接池,之前我們其實也用到 go 自帶的 pool 來做,但是當對 pool 數據進行更新時,需要加鎖,所以性能一直起不來,後來改成了環形隊列,然後對數據的操作全部通過原子操作方式,就實現了無鎖操作,大大提高的併發性能。 環形隊列的代碼,也給你安排上,可以直接看這篇文章 Go 語言核心手冊 - 10. 原子操作。
實現邏輯
這個是 hal-proxy 的邏輯實現圖,畫了 2 天,包含所有核心對象的交互方式,這裏就不去細講,能掌握多少,靠大家自己領悟。
盡信書則不如無書,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/f2hepLraaqUgRKqq9ZKKsQ