買單俠微服務的API網關演化之路


伴隨着買單俠業務的快速發展,能夠支持獨立開發、獨立部署、獨立擴展的微服務在秦蒼得到了廣泛應用和蓬勃發展,短短3年左右時間,已經發展到了300+個微服務,並且還在快速增長中。


研發逐漸意識到伴隨着微服務規模化的增長,必需要重視微服務的基礎設施建設(API網關、服務註冊中心、調用鏈跟蹤等)才能保持開發效率和產品的質量。


API網關作爲訪問微服務的大門, 是訪問後臺服務的入口,作爲最常用的基礎服務之一,其重要性不言而喻。在買單俠微服務的發展道路上,經過了以下摸索發展階段,希望能給規模化應用微服務的攻城獅們更多參考和啓發。


原始時代-沒有API網關的數百微服務

最初在沒有API網關的日子,我們部署在阿里雲上的服務全部使用阿里雲的負載均衡SLB直接進行通信。不同的服務不同的環境配置不同的SLB地址,運維維護的配置文件存在着大量的SLB地址,稍不留意配置錯誤,就會影響發佈上線。


客戶端直接和各個服務直接交互,客戶端和服務端有強耦合。服務端的波動會直接影響到客戶端。


各個服務也是任意調用,公司服務調用的拓撲圖,其實是一個混亂、混沌的蜘蛛網狀圖。對數百個這樣微服務而言,沒有隔離、沒有把控,不僅容易引起問題,而且各個服務的通用需求認證、監控、轉換等功能需要多次實現,無法重用。



青銅時代-面向服務的網關Spring Cloud Zuul

痛則思變,買單俠的微服務需要一個入口,就是API網關,幫助解耦客戶端和具體後端微服務,它在微服務架構中很像面向對象設計模式中的Facade模式封裝內部系統的架構,並且提供API給各個客戶端作爲服務入口。


由於買單俠微服務技術路線採用Spring Cloud,基於Netflix開源的基礎組件搭建基礎設施,例如服務註冊中心Eureka,在API網關選項中,考慮和Eureka、Ribbon等的兼容,Zuul成了我們的不二選擇。


作爲API網關,Zuul能根據簡單配置就能完成PATH和URL的路由映射轉發。


Zuul提供了一個技術框架從請求抵達(pre),請求路由(route)到請求結束(post)以及請求出錯(error)各個階段Zuul都有專門類型的過濾器filter及示例,參見下圖。開發可以在請求路由轉發過程中的各個階段實現自己的過濾器完成邏輯控制。

Zuul可以定時掃描指定目錄下用戶自己實現的groovy過濾器,通過groovy類加載器動態加載,從而在不用重啓API網關下達到動態添加、更新過濾器。


由於買單俠的微服務使用了基於Spring Cloud Netflix的Eureka作爲服務註冊發現,Zuul也能作爲Eureka Client從Eureka Server自動發現註冊在上面的服務。


這樣服務名可以作爲發往網關請求的RootPath,比如業務線定義了一個API: /user 給手機端,以前得在Zuul添加mapping, /user --> /serviceName/user, 添加時需要改APIGateway的配置,改完需要重啓。


現在,只要暴露給手機端是/demo-service/user, demo-service是服務名,經過Zuul時不用任何配置,它會根據eureka的服務名自動routing到demo-service, 然後調用user,所以serviceName 可以作爲RootPath。無需額外配置,非常方便。

在產品線入口,買單俠開始引入Zuul作爲API網關作爲API門戶管理轉發請求到後端服務,並支持了請求校驗和跨域功能。走出了原始時代的混沌。


白銀時代-支持灰度發佈的服務分組入口Zuul

Zuul開始幫助我們解耦了客戶端和具體後端微服務,但對於上百微服務的規模化管理挑戰一直存在,我們希望能達到微服務的分組和系統化管理。


比如一條產品線,可能會有直銷商城、賬務、審覈、基礎應用服務(字典服務)等業務系統(分組的服務)。而每個分組,會期望在請求抵達自己業務系統中做一些通用操作。


在這種背景下,我們期望Zuul成爲服務分組後各個業務系統自己的入口服務。爲此,我們改造了我們服務發現的調用方式。

類型

調用方式

服務分組內服務發現

直接調用

跨服務分組的服務發現

調用發給Zuul,再由Zuul轉發到具體服務

服務分組內的服務每個服務註冊到Eureka的metadata中專門有一項說明自己服務分組內的入口API網關Zuul的服務ID。然後服務調用時,先發現對應服務的Zuul是否和自己本身分組的Zuul服務ID一樣,是就直接調用,否則請求自動發往對應服務Zuul,然後路由轉發到對應服務。


Zuul可以自治化管理自己業務系統。比如我們要對一個業務系統中的部分服務做灰度發佈。那麼只需要更改直銷商城業務系統API網關。


所以我們在Zuul裏實現了灰度發佈的策略管理,可以選擇權重策略,白名單策略,用戶區域策略等對用戶進行自定義路由分流。


比如白名單策略,Zuul可以根據請求裏的header信息,例如用戶token來判斷是否白名單中用戶路由到指定服務,這樣發佈系統時,可以在舊服務在線情況下,發佈新版本服務。讓我們的QA作爲白名單策略中用戶路由到新版本服務系統中進行測試。測試通過後再切換流量到新版本服務,關閉老服務。


另外,買單俠微服務部署開始應用docker技術解決快速部署並達到跨環境標準一致。上百微服務不可能一次性遷移到容器環境,我們採取了分業務系統,按照服務分組逐步遷移的方式。這裏的一個挑戰是服務容器化後,基於overlay網絡,有了獨立於阿里雲ECS機器的容器IP,現在註冊到Eureka的就是容器IP。


在同一個集羣內,即容器化的服務間基於容器IP是可以相互訪問,但是集羣外,即非容器化的服務根據容器IP是沒法訪問容器化的服務,網絡是不同的。


阿里雲容器平臺推薦的遷移方案是給每個容器化服務綁定SLB(server load balance)一個靜態IP地址來實現容器集羣外服務訪問容器服務。但是對於上百規模的微服務,每個服務配置SLB是巨大的工程,特別我們還有QA,Staging,Production三套環境,工作量翻了三倍。


API網關Zuul在這裏繼續扮演了極其重要的角色,簡化解決了我們的這個遷移問題。我們僅僅把API網關Zuul作爲每個服務分組的代理入口綁定了SLB,並且把這個靜態IP作爲Zuul的hostname註冊到Eureka。服務分組外的服務對容器內服務1的訪問包括下面幾步:


1.  先獲取到該服務1註冊到Eureka的metadata,得到服務分組入口Zuul service ID。從Eureka中查到Zuul註冊的hostname即SLB靜態IP地址。

2.  按照SLB發送請求給Zuul,請求路徑中攜帶服務1的serviced.

3.  Zuul根據serviceId自動路由到服務1。



由此可見,Zuul作爲每個服務分組的入口在買單俠微服務體系中作用巨大,解決了灰度發佈、容器遷移等一系列關鍵問題,並將繼續扮演舉足輕重的角色。


黃金時代-面向終端用戶的出入口網關Nginx

當衆多服務分組有了自己的入口Zuul,在產品線面向用戶的入口處網關又發現了一種尷尬情況。


原來有一個直接面向用戶的Zuul將用戶請求轉發給後臺服務,現在還有一個管理服務分組的入口網關,將服務分組外的後臺請求轉發給組內服務。


出現了兩個入口!

 

同時,Zuul由於啓用了Spring Boot Actuator,暴露了Log, Trace, Dump等敏感Endpoint,在安全方面引起了我們的擔心顧慮。並且基於服務註冊發現,理論上你知道serviceId可以把任意請求轉發給對應服務。


面向終端用戶,Zuul是最合適的入口選擇嗎?


並且在我們性能壓力測試下,Zuul雖然適合編程實現業務邏輯,本身的性能並不佔優,特別更改配置重啓服務通常要2分鐘左右非常慢。通常要部署多個Zuul容器保證高可用,還是有一定資源消耗。


對於終端用戶,隱藏內部服務細節,並提供高性能的轉發服務,Nginx其實是非常不錯的選擇。並在我們產品線開始推廣使用。並且在一條產品線上可被多個業務系統(服務分組)共享使用,比如直銷商城和直銷客戶,從而提高資源利用率。



解決了入口問題,出口其實也是非常需要引起重視的。


我們的微服務會有一些對外渠道,比如資金源需要訪問不同的資金渠道,支付需要訪問不同的支付渠道,不同渠道往往有不同的安全性要求,例如僅僅允許運行IP白名單的服務訪問,需要特定證書。之前訪問這些渠道都是由具體服務自己直接負責。


當業務規模,服務規模增大,對外出口的訪問管理也容易引起混亂,對統一出口的需求變得強烈。


容器部署讓統一出口成爲必要需求,因爲容器會在集羣內機器上隨機部署,具有隨機IP,而給容器集羣內所有機器配置白名單,裝證書並不現實。


我們需要統一的API出口網關,在這裏我們可以統一管理證書,提供固定IP。實際上就是一個代理幫助我們轉發請求到外部渠道服務。


Nginx再次以優異表現勝任了我們的需求,擔當我們的出口API網關,我們親切地稱呼它outlets。


每臺Nginx代理固定在一臺ECS上,提供ECS固定IP給外部數據提供商。Nginx啓動速度快,並能動態加載配置,平滑升級。容器可以訪問出口API網關來代理訪問外部依賴服務。


白金時代-接入層網關探索升級從Nginx到Kong

在我們使用Nginx作爲出入口網關過程中,我們也關注到基於Nginx的Kong。作爲接入層網關,Kong繼承Nginx的優異性能表現並且體現了更多的擴展性和網關管理功能。



基於OpenResty,所有對Kong的配置操作都通過REST API完成並且即時生效。


由於Kong基於Nginx,很多基本配置都可以映射到Nginx。


Kong一個非常吸引人的特色是它的豐富插件,有認證,安全,限流,監控,轉換,日誌等多種類型插件,能輕鬆配置完成訪問控制,黑白名單設置,限流,跨域等等功能。


當然,由於Kong的靈活性,對於Kong的權限管理和使用流程上還有待規範。


不久我們可預期各條產品線不僅具有對外的接入層網關Kong,在這裏可以基於Kong的插件實現業務無關的出入口基本管理,而且在它後面是由獨立Zuul作爲入口的各個業務系統,開發可以利用Zuul實現自己業務相關的入口控制管理。


總結

買單俠微服務的API網關演化之路着重分享了買單俠微服務體系中,API網關建設從無到有,從少到多,從單一到多元化的演進過程,下表總結了目前我們主要採用的網關技術方案。


在保障基本路由轉發外,API網關更在買單俠的微服務治理中扮演重要角色,隨着規模化管理和業務需求,其在服務分組管控、灰度發佈、熔斷監控、容器化遷移、統一出入口管理等場景都有深入實踐,並且還在不斷演進發展中。



12

作者簡介


林丹,現任上海秦蒼(買單俠)信息科技有限公司基礎架構部架構師,畢業於哈爾濱工業大學軟件工程專業,加入秦蒼之前,曾在Autodesk、Blackboard公司任職。專注於SpringCloud、Docker、雲計算、SaaS Performance、持續交付等相關領域,積累了豐富的互聯網架構設計經驗。目前主要負責微服務基礎設施、Docker及CI/CD、前端等相關工作。









OmniStack

秦蒼Geek的聚集地

長按二維碼關注我們

伴隨着買單俠業務的快速發展,能夠支持獨立開發、獨立部署、獨立擴展的微服務在秦蒼得到了廣泛應用和蓬勃發展,短短3年左右時間,已經發展到了300+個微服務,並且還在快速增長中。


研發逐漸意識到伴隨着微服務規模化的增長,必需要重視微服務的基礎設施建設(API網關、服務註冊中心、調用鏈跟蹤等)才能保持開發效率和產品的質量。


API網關作爲訪問微服務的大門, 是訪問後臺服務的入口,作爲最常用的基礎服務之一,其重要性不言而喻。在買單俠微服務的發展道路上,經過了以下摸索發展階段,希望能給規模化應用微服務的攻城獅們更多參考和啓發。


原始時代-沒有API網關的數百微服務

最初在沒有API網關的日子,我們部署在阿里雲上的服務全部使用阿里雲的負載均衡SLB直接進行通信。不同的服務不同的環境配置不同的SLB地址,運維維護的配置文件存在着大量的SLB地址,稍不留意配置錯誤,就會影響發佈上線。


客戶端直接和各個服務直接交互,客戶端和服務端有強耦合。服務端的波動會直接影響到客戶端。


各個服務也是任意調用,公司服務調用的拓撲圖,其實是一個混亂、混沌的蜘蛛網狀圖。對數百個這樣微服務而言,沒有隔離、沒有把控,不僅容易引起問題,而且各個服務的通用需求認證、監控、轉換等功能需要多次實現,無法重用。



青銅時代-面向服務的網關Spring Cloud Zuul

痛則思變,買單俠的微服務需要一個入口,就是API網關,幫助解耦客戶端和具體後端微服務,它在微服務架構中很像面向對象設計模式中的Facade模式封裝內部系統的架構,並且提供API給各個客戶端作爲服務入口。


由於買單俠微服務技術路線採用Spring Cloud,基於Netflix開源的基礎組件搭建基礎設施,例如服務註冊中心Eureka,在API網關選項中,考慮和Eureka、Ribbon等的兼容,Zuul成了我們的不二選擇。


作爲API網關,Zuul能根據簡單配置就能完成PATH和URL的路由映射轉發。


Zuul提供了一個技術框架從請求抵達(pre),請求路由(route)到請求結束(post)以及請求出錯(error)各個階段Zuul都有專門類型的過濾器filter及示例,參見下圖。開發可以在請求路由轉發過程中的各個階段實現自己的過濾器完成邏輯控制。

Zuul可以定時掃描指定目錄下用戶自己實現的groovy過濾器,通過groovy類加載器動態加載,從而在不用重啓API網關下達到動態添加、更新過濾器。


由於買單俠的微服務使用了基於Spring Cloud Netflix的Eureka作爲服務註冊發現,Zuul也能作爲Eureka Client從Eureka Server自動發現註冊在上面的服務。


這樣服務名可以作爲發往網關請求的RootPath,比如業務線定義了一個API: /user 給手機端,以前得在Zuul添加mapping, /user --> /serviceName/user, 添加時需要改APIGateway的配置,改完需要重啓。


現在,只要暴露給手機端是/demo-service/user, demo-service是服務名,經過Zuul時不用任何配置,它會根據eureka的服務名自動routing到demo-service, 然後調用user,所以serviceName 可以作爲RootPath。無需額外配置,非常方便。

在產品線入口,買單俠開始引入Zuul作爲API網關作爲API門戶管理轉發請求到後端服務,並支持了請求校驗和跨域功能。走出了原始時代的混沌。


白銀時代-支持灰度發佈的服務分組入口Zuul

Zuul開始幫助我們解耦了客戶端和具體後端微服務,但對於上百微服務的規模化管理挑戰一直存在,我們希望能達到微服務的分組和系統化管理。


比如一條產品線,可能會有直銷商城、賬務、審覈、基礎應用服務(字典服務)等業務系統(分組的服務)。而每個分組,會期望在請求抵達自己業務系統中做一些通用操作。


在這種背景下,我們期望Zuul成爲服務分組後各個業務系統自己的入口服務。爲此,我們改造了我們服務發現的調用方式。

類型

調用方式

服務分組內服務發現

直接調用

跨服務分組的服務發現

調用發給Zuul,再由Zuul轉發到具體服務

服務分組內的服務每個服務註冊到Eureka的metadata中專門有一項說明自己服務分組內的入口API網關Zuul的服務ID。然後服務調用時,先發現對應服務的Zuul是否和自己本身分組的Zuul服務ID一樣,是就直接調用,否則請求自動發往對應服務Zuul,然後路由轉發到對應服務。


Zuul可以自治化管理自己業務系統。比如我們要對一個業務系統中的部分服務做灰度發佈。那麼只需要更改直銷商城業務系統API網關。


所以我們在Zuul裏實現了灰度發佈的策略管理,可以選擇權重策略,白名單策略,用戶區域策略等對用戶進行自定義路由分流。


比如白名單策略,Zuul可以根據請求裏的header信息,例如用戶token來判斷是否白名單中用戶路由到指定服務,這樣發佈系統時,可以在舊服務在線情況下,發佈新版本服務。讓我們的QA作爲白名單策略中用戶路由到新版本服務系統中進行測試。測試通過後再切換流量到新版本服務,關閉老服務。


另外,買單俠微服務部署開始應用docker技術解決快速部署並達到跨環境標準一致。上百微服務不可能一次性遷移到容器環境,我們採取了分業務系統,按照服務分組逐步遷移的方式。這裏的一個挑戰是服務容器化後,基於overlay網絡,有了獨立於阿里雲ECS機器的容器IP,現在註冊到Eureka的就是容器IP。


在同一個集羣內,即容器化的服務間基於容器IP是可以相互訪問,但是集羣外,即非容器化的服務根據容器IP是沒法訪問容器化的服務,網絡是不同的。


阿里雲容器平臺推薦的遷移方案是給每個容器化服務綁定SLB(server load balance)一個靜態IP地址來實現容器集羣外服務訪問容器服務。但是對於上百規模的微服務,每個服務配置SLB是巨大的工程,特別我們還有QA,Staging,Production三套環境,工作量翻了三倍。


API網關Zuul在這裏繼續扮演了極其重要的角色,簡化解決了我們的這個遷移問題。我們僅僅把API網關Zuul作爲每個服務分組的代理入口綁定了SLB,並且把這個靜態IP作爲Zuul的hostname註冊到Eureka。服務分組外的服務對容器內服務1的訪問包括下面幾步:


1.  先獲取到該服務1註冊到Eureka的metadata,得到服務分組入口Zuul service ID。從Eureka中查到Zuul註冊的hostname即SLB靜態IP地址。

2.  按照SLB發送請求給Zuul,請求路徑中攜帶服務1的serviced.

3.  Zuul根據serviceId自動路由到服務1。



由此可見,Zuul作爲每個服務分組的入口在買單俠微服務體系中作用巨大,解決了灰度發佈、容器遷移等一系列關鍵問題,並將繼續扮演舉足輕重的角色。


黃金時代-面向終端用戶的出入口網關Nginx

當衆多服務分組有了自己的入口Zuul,在產品線面向用戶的入口處網關又發現了一種尷尬情況。


原來有一個直接面向用戶的Zuul將用戶請求轉發給後臺服務,現在還有一個管理服務分組的入口網關,將服務分組外的後臺請求轉發給組內服務。


出現了兩個入口!

 

同時,Zuul由於啓用了Spring Boot Actuator,暴露了Log, Trace, Dump等敏感Endpoint,在安全方面引起了我們的擔心顧慮。並且基於服務註冊發現,理論上你知道serviceId可以把任意請求轉發給對應服務。


面向終端用戶,Zuul是最合適的入口選擇嗎?


並且在我們性能壓力測試下,Zuul雖然適合編程實現業務邏輯,本身的性能並不佔優,特別更改配置重啓服務通常要2分鐘左右非常慢。通常要部署多個Zuul容器保證高可用,還是有一定資源消耗。


對於終端用戶,隱藏內部服務細節,並提供高性能的轉發服務,Nginx其實是非常不錯的選擇。並在我們產品線開始推廣使用。並且在一條產品線上可被多個業務系統(服務分組)共享使用,比如直銷商城和直銷客戶,從而提高資源利用率。



解決了入口問題,出口其實也是非常需要引起重視的。


我們的微服務會有一些對外渠道,比如資金源需要訪問不同的資金渠道,支付需要訪問不同的支付渠道,不同渠道往往有不同的安全性要求,例如僅僅允許運行IP白名單的服務訪問,需要特定證書。之前訪問這些渠道都是由具體服務自己直接負責。


當業務規模,服務規模增大,對外出口的訪問管理也容易引起混亂,對統一出口的需求變得強烈。


容器部署讓統一出口成爲必要需求,因爲容器會在集羣內機器上隨機部署,具有隨機IP,而給容器集羣內所有機器配置白名單,裝證書並不現實。


我們需要統一的API出口網關,在這裏我們可以統一管理證書,提供固定IP。實際上就是一個代理幫助我們轉發請求到外部渠道服務。


Nginx再次以優異表現勝任了我們的需求,擔當我們的出口API網關,我們親切地稱呼它outlets。


每臺Nginx代理固定在一臺ECS上,提供ECS固定IP給外部數據提供商。Nginx啓動速度快,並能動態加載配置,平滑升級。容器可以訪問出口API網關來代理訪問外部依賴服務。


白金時代-接入層網關探索升級從Nginx到Kong

在我們使用Nginx作爲出入口網關過程中,我們也關注到基於Nginx的Kong。作爲接入層網關,Kong繼承Nginx的優異性能表現並且體現了更多的擴展性和網關管理功能。



基於OpenResty,所有對Kong的配置操作都通過REST API完成並且即時生效。


由於Kong基於Nginx,很多基本配置都可以映射到Nginx。


Kong一個非常吸引人的特色是它的豐富插件,有認證,安全,限流,監控,轉換,日誌等多種類型插件,能輕鬆配置完成訪問控制,黑白名單設置,限流,跨域等等功能。


當然,由於Kong的靈活性,對於Kong的權限管理和使用流程上還有待規範。


不久我們可預期各條產品線不僅具有對外的接入層網關Kong,在這裏可以基於Kong的插件實現業務無關的出入口基本管理,而且在它後面是由獨立Zuul作爲入口的各個業務系統,開發可以利用Zuul實現自己業務相關的入口控制管理。


總結

買單俠微服務的API網關演化之路着重分享了買單俠微服務體系中,API網關建設從無到有,從少到多,從單一到多元化的演進過程,下表總結了目前我們主要採用的網關技術方案。


在保障基本路由轉發外,API網關更在買單俠的微服務治理中扮演重要角色,隨着規模化管理和業務需求,其在服務分組管控、灰度發佈、熔斷監控、容器化遷移、統一出入口管理等場景都有深入實踐,並且還在不斷演進發展中。



12

作者簡介


林丹,現任上海秦蒼(買單俠)信息科技有限公司基礎架構部架構師,畢業於哈爾濱工業大學軟件工程專業,加入秦蒼之前,曾在Autodesk、Blackboard公司任職。專注於SpringCloud、Docker、雲計算、SaaS Performance、持續交付等相關領域,積累了豐富的互聯網架構設計經驗。目前主要負責微服務基礎設施、Docker及CI/CD、前端等相關工作。








OmniStack

秦蒼Geek的聚集地

長按二維碼關注我們

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