大流量場景下如何雲淡風輕地進行線上發佈?

簡介: 本文介紹了微服務治理下金絲雀發佈的能力,解決了發佈期間少許流量驗證新功能的問題。git


不少互聯網公司在半夜發佈的另一個重要緣由是不具有可灰度能力,新版本存在 bug 或者其它緣由會影響線上的客戶,無奈之下只能選擇在半夜進行發佈來減小影響面。github

咱們知道默認狀況下,不管是 Kubernetes 仍是 ECS,新老版本都存在的狀況下會根據特定的負載均衡算法隨機地路由到不一樣的實例上,隨機意味着出問題也會隨機出現。咱們須要一套動態路由來完成灰度發佈的解決方案。算法

在 RPC 領域,咱們稱灰度發佈爲動態路由,動態路由的意思是指流量能夠動態地路由到指定的實例上。shell

動態路由場景

動態路由是微服務裏很是核心的功能,流量動態路由意味着能夠作很是多的事情。由此衍生出各個場景:json

  • 金絲雀發佈:只有知足特定規則(好比 Query Parameter、HEADER、COOKIE 中某些 KEY 知足一些條件)或者是固定流量比例的流量纔會進入新版本,其它流量都路由到老版本上。

 

  • 同機房優先路由:當公司規模擴大以後,應用會跨機房部署來達到高可用的目的。因爲異地跨機房調用出現的網絡延遲問題,須要確保服務消費方能優先調用相同機房的服務消費方,這就須要同機房優先路由的能力。

 

  • 標籤路由:金絲雀發佈的新場景。金絲雀發佈通常只有新和老兩個版本,標籤路由能夠在線上部署多個版本,每一個版本都對於一個標籤。
  • 全鏈路灰度:在業務比較複雜,服務調用鏈路較長的場景下,每一個應用都須要設置路由規則會顯得很是繁瑣,全鏈路灰度在金絲雀/標籤路由的基礎上加上了 "標籤透傳" 的能力,讓灰度流量只在灰度版本之間路由。

 

接下來我會分幾篇文章詳細講一下這幾個場景,今天咱們先來聊聊金絲雀發佈。金絲雀發佈可讓咱們在白天流量高峯喝着茶吃着瓜子進行線上發佈,不須要在半夜爲發佈的事情而苦惱。網絡

大流量下的應用部署現狀

應用 Demo

Demo 以 Spring Cloud 爲例,服務調用鏈路以下圖所示:架構

 

流量從 Netflix Zuul 對應的 Ingress 進來,會調用 SC-A 應用對應的服務,SC-A 應用內部調用 SC-B 應用的服務,SC-B 應用內部調用 SC-C 應用的服務。SC-A 有線上版本和灰度版本這兩個版本。負載均衡

Helm 部署 Demo

Demo 爲純開源 Spring Cloud 架構,項目地址:https://github.com/aliyun/alibabacloud-microservice-demo/tree/master/microservice-doc-demo/traffic-management。curl

部署完畢後,阿里雲容器服務上的工做負載狀況以下:微服務

 

咱們經過 "while true; do curl http://{ip:port}/A/a;echo;done" shell 命令不斷地去訪問 Spring Cloud 服務,各個服務的做用僅僅是打印當前服務的IP,這樣咱們能夠看到總體調用鏈路:

while true; do curl http://{ip:port}/A/a;echo;done
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
...

從這個過程咱們明顯能夠看出 Netflix Zuul -> SC-A 這條鏈路是隨機訪問的,因爲 SC-A 的線上版本和灰度版本各只有 1 個 Pod,因此隨機打印了這兩個 POD 的 IP。

開源金絲雀的實現

動態路由的本質就是尋址過程當中去找符合條件的實例地址。

Apache Dubbo 提供了 RouterChain 的能力去過濾 Invoker 列表,RouterChain 內部維護着 Router 列表,每一個 Router 都會作過濾 Invoker 的邏輯,最後將 Invoker 列表交付給 LoadBalance 作負載均衡獲取最後的 Invoker。

ScriptRouter,ConditionRouter 和 TagRouter 這些內置的 Router 內部都是 Dubbo 自帶的動態路由能力。

Spring Cloud 的路由能力由 Ribbon 實現。Ribbon 設計了 ILoadBalancer 接口用於獲取 Server 列表,最後將這個列表交付給 IRule 作負載均衡策略獲取最後的 Server。這塊在設計上跟 Dubbo 相比是有缺陷的。

Spring Cloud Ribbon 裏的 ILoadBalancer 至關因而 Dubbo RouterChain 裏的一個 Router,IRule 至關因而 Dubbo LoadBalance。

最新版本的 Spring Cloud 新增了 Spring Cloud LoadBalancer 組件代替 Ribbon 用於作負載均衡,Spring Cloud LoadBalancer 裏的 ServiceInstanceListSupplier 用於獲取實例列表信息,ReactiveLoadBalancer 使用負載均衡策略獲取最後的實例。

這是 3 者對應組件的說明:

 

Apache Dubbo 雖然內置了各類 Router,但實際使用下來卻有很是多的問題。好比 TagRouter 跟 IP 綁定,在 Kubernetes 下沒法工做;ScriptRouter 用了 ScriptEngine 去作腳本的處理,會有性能問題;Dubbo Admin 的使用體驗很是糟糕等等。

Spring Cloud 官方並無提供動態路由的能力,只有社區上的一些開發者本身去擴展了這個能力,社區上也沒有任何的 UI 交互界面。

這時候 MSE 告訴你,MSE 的微服務解決方案提供了動態路由的能力,不須要作任何的代碼和配置的修改,就能使用 OPEN API 或者 UI 交互去完成金絲雀發佈。只需將您的應用接入 MSE 服務治理,您就能享受到金絲雀能力。

只要你的應用是基於 Spring Cloud 或 Dubbo 最近五年內的版本開發,就能直接使用完整的 MSE 微服務治理能力,不須要修改任何代碼和配置。

無需任何代碼修改就能夠作到動態路由的能力,這不香嗎?

MSE 金絲雀能力

應用接入 MSE 便可享受 MSE 提供的動態路由能力,無需任何代碼修改。

引入標籤概念

MSE 引入了標籤的概念,能夠針對每一個標籤設置路由規則,知足該路由規則的流量會路由到這個標籤對應的實例下。咱們將 Spring Cloud Demo 進行一點改造,給 SC-A 的灰度版本打上 "blue" 標籤( Helm 已經完成了這個步驟)。

 

接入 MSE 後,MSE 默認會給應用分配一個 100% 路由到未打標實例的路由規則。此時,咱們繼續經過 "while true; do curl http://{ip:port}/A/a;echo;done" shell 命令去執行,這個時候調用 SC-A 所有返回線上版本的 IP:

while true; do curl http://{ip:port}/A/a;echo;done
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
A[10.0.0.73] -> B[10.0.0.180] -> C[10.0.0.72]
...

設置金絲雀路由規則

咱們在 MSE 上的應用詳情頁裏的金絲雀 Tab 頁裏設置 HEADER 裏 env 這個 KEY 的值爲 test 的金絲雀路由條件:

 

傳入 HEADER 繼續使用 shell 執行:

while true; do curl -H "env:test" http://139.196.200.40/A/a;echo;done
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
A1[10.0.0.20] -> B[10.0.0.180] -> C[10.0.0.72]
...

這個時候咱們發現知足金絲雀規則的流量都去了 SC-A 的灰度版本。

金絲雀路由規則解析

你們看到金絲雀路由規則界面上有兩種分別,分別是流量比例流量規則:

 

流量規則:表示知足該規則的流量會路由到對應標籤(本文使用 blue 做爲灰度標籤)實例上。好比本文例子中 HEADER 裏 env=test 的流量必定會去 blue 標籤對應的實例。

流量比例:不知足任何流量規則的流量會按照流量百分比進行路由。好比本文例子中不知足 HEADER 裏 env=test 的流量會以 100% 的規則路由到未打標的實例上,因爲是 100%,因此那些不知足規則的流量所有都去了未打標實例上(本文未打標表示線上版本)。

MSE 提供的流量規則裏的條件支持 HEADER、Query Parameter、COOKIE 以及 Request BODY

Query Parameter、HEADER、COOKIE 和 Request Body 除了支持常規的運算符外,還支持 in(白名單),對 100 取模和百分比。這裏的百分比並非比例規則中的總流量百分比,而是指對應參數的 hash 值取模,這樣就可讓固定的值永遠知足路由條件(若是按照流量比例,用戶 A 此次訪問的是線上版本,下次可能會訪問灰度版本)。舉個例子,若是 HEADER 中帶有用戶 ID,我讓想部分用戶永遠可以訪問灰度實例,這個時候能夠對用戶 ID 的 hash 值取模去完成(固然,這個也能夠經過白名單去操做,白名單的缺點並不隨機,須要輸入各個名單)。

Request Body 目前支持解析 json 字符串,好比以下字符串:

{  
  "a": "aa",
  "b": [
    1,2,3
  ],
  "c": [
    {
      "d": "dd"
    }
  ],
  "e": {
    "f": "ff"
  }
}

JSON 訪問表達式 .a 的值爲 aa。
JSON 訪問表達式 .b[0] 的值爲 1。
JSON 訪問表達式 .c[0].d 的值爲 dd。
JSON 訪問表達式 .e.f 的值爲 ff。

總結

本文介紹了微服務治理下金絲雀發佈的能力,解決了發佈期間少許流量驗證新功能的問題。您的應用只需接入 MSE 服務治理,無需任何操做便可享受到動態路由的能力。除了 MSE(微服務引擎),金絲雀發佈還被 EDAS、SAE 等雲產品集成。

做者:中間件小哥

原文連接 

本文爲阿里雲原創內容,未經容許不得轉載

相關文章
相關標籤/搜索