天天看點

微服務治理實踐 | 金絲雀釋出

本文是《微服務治理實踐》系列篇的第三篇文章,主要分享 Spring Cloud & Dubbo 微服務架構下的金絲雀釋出。

第一篇:

《微服務治了解密》 第二篇: 《微服務治理實踐:服務查詢》

前言

阿裡巴巴集團内部有不少故障是因為釋出直接或間接引起。是以提升釋出的品質,減少錯誤的發生,是有效減少線上故障的一個關鍵環節。

為什麼大部分的故障和釋出相關?因為釋出是整個功能更新到線上的最後一個環節,一些研發過程中累計的問題,在最後釋出環節才會觸發。同時釋出本身也是一個複雜的過程,在釋出過程中,往往容易出現一些錯誤操作或者遺漏關鍵操作。

日常釋出中,我們常常會有如下一些錯誤的想法:

  • 這次改動的内容比較小,而且上線要求比較急,就不需要測試直接釋出上線好了
  • 釋出不需要走灰階流程,快速釋出上線即可
  • 灰階釋出沒有什麼用,就是一個流程而已,釋出完就直接釋出線上,不用等待觀察
  • 雖然灰階釋出很重要,但是灰階環境很難搭建,耗時耗力優先級并不高

這些想法都可能讓我們進行一次錯誤的釋出。

阿裡巴巴内部有安全生産三闆斧概念: 可灰階、可觀測、可復原。所有研發同學必須要掌握釋出系統的灰階、觀測和復原功能如何使用。

今天我們來聊聊灰階釋出。

灰階釋出政策

灰階釋出是釋出整個過程中一個非常重要的環境。目前灰階釋出政策有這幾種:

  • 藍綠釋出(Blue-Green Deployment)
微服務治理實踐 | 金絲雀釋出

通過部署兩套環境來解決新老版本的釋出問題。如果新版本(New Version)發生問題要進行復原的時候,直接通過切流将流量全部切到老版本(Old Version)上。

優點:更新切換和回退比釋出復原迅速

缺點:成本較高,需要部署兩套環境。如果新版本中基礎服務出現問題,會瞬間影響全網使用者;如果新版本有問題也會影響全網使用者

  • 金絲雀釋出(Canary Release)
微服務治理實踐 | 金絲雀釋出

優點:靈活,政策自定義,可以按照流量或具體的内容進行灰階(比如不同賬号,不同參數),出現問題不會影響全網使用者

缺點:沒有覆寫到所有的使用者導緻出現問題不好排查

  • 滾動釋出(Rolling Release)
微服務治理實踐 | 金絲雀釋出

金絲雀釋出的一種變化。通過分批釋出的方式進行多批釋出(比如一共 9 個執行個體,分 3 批,每次 3 個執行個體釋出),适合大規模應用釋出

優點:出現問題不會影響全網使用者,适合大規模應用釋出

缺點:釋出和復原周期較長

本文将介紹 Spring Cloud & Dubbo 微服務架構下的金絲雀釋出。

微服務金絲雀釋出開源實作

微服務金絲雀釋出的核心是服務路由,隻要能控制服務路由的邏輯,就能确定流量的走向,确定流量走向也就意味着可以控制路由到任意節點。

目前 Spring Cloud 開源國内有

Nepxion Discovery

這款架構支援灰階釋出,或是開發者自己實作 Ribbon 裡對應的接口即可。 Apache Dubbo 開發者實作 Dubbo 提供的 Router 或 LoadBalance 即可;另外 Dubbo Admin 界面提供了條件路由、标簽路由功能也可以完成動态路由功能。

Spring Cloud

有這麼一個 Spring Cloud 服務調用場景:

微服務治理實踐 | 金絲雀釋出
  • Query Parameter 中存在 name=jim 的請求,路由到 192.168.1.1 節點
  • Header 中存在 Test=1 的請求,路由到 192.168.1.2 節點
  • Cookie 中存在 lang=zh-cn 的請求,路由到 192.168.1.3 節點

這些不同類型的請求資料決定着 Spring Cloud 的服務路由邏輯。Spring Cloud 服務路由元件為 Netflix Ribbon(Spring Cloud Hoxton 引入了 Spring Cloud LoadBalancer 用于替換 Netflix Ribbon)。Ribbon 内部的 ILoadBalancer 接口用于擷取執行個體(Server)清單資訊,IRule 接口用于擷取最終的确定的執行個體(Server)。是以,如何使用/擴充這兩塊接口是 Spring Cloud 動态路由的核心。

不論是 Netflix Ribbon 或者 Spring Cloud LoadBalancer,它們在路由的過程中都無法擷取 Request 資訊,Request 資訊存儲着使用者請求内容中的所有資料。為了這個這個解決,需要引入 ThreadLocal 來透傳 Request 資料。

Apache Dubbo

Apache Dubbo 不論是 Router 或者 LoadBalance,它們提供的方法内部都可以擷取到 Invocation。有了 Invocation 之後可以擷取調用的方法、調用的參數類型、調用的參數值、Attachment。

這些 Invocation 裡的内容可以決定過濾掉哪些 Invoker,比如定義了一個 CanaryRouter 對于 getEnv 方法路由到灰階 Invoker,否則路由到其它 Invoker(每個節點注冊的時候設定一個自定義的 parameter gray 到 url 中,表示這是一個灰階節點):

public class CanaryRouter extends AbstractRouter {
    @Override
    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        List<Invoker> normal = new ArrayList<>();
        List<Invoker> canary = new ArrayList<>();
        for(Invoker invoker : invokers) {
            if(invoker.getUrl().getParameter("gray", false)) {
                canary.add(invoker);
            } else {
                normal.add(invoker);
            }
        }
        if(invocation.getMethodName().equals("getEnv")) {
            return canary;
        } else {
            return normal;
        }
    }
}           

EDAS 金絲雀釋出實踐

EDAS 金絲雀釋出支援 Apache Dubbo 和 Spring Cloud 微服務架構。金絲雀釋出的底層使用 Java Agent 技術通過位元組碼增強 Apache Dubbo 和 Spring Cloud 的路由邏輯。由于是使用 Agent 技術,而且在抽象類上進行了攔截,這使得對 Apache Dubbo 和 Spring Cloud 的 的版本以及注冊中心都有了更全面的支援。

  • 版本: Apache Dubbo 支援 2.5.x, 2.6.x 以及 2.7.x;Spring Cloud 支援 Dalston、Edgware、Finchley 以及 Hoxton(暫不支援 Hoxton 裡的 Spring Cloud LoadBalancer 負載均衡元件)
  • 注冊中心: 支援 Zookeeper,Consul,Eureka,Nacos,Etcd 等注冊中心

下面,我們開始體驗 EDAS 上的金絲雀釋出。

建立應用

建立 Provider 和 Consumer 應用:

微服務治理實踐 | 金絲雀釋出

Provider 請注意填寫至少 2 個 Pod 數:

微服務治理實踐 | 金絲雀釋出

全部建立完畢後,調用 consumer 對外暴露的位址确認 consumer 可以順利調用 provider 服務。

金絲雀釋出

Provider 進行應用部署,選擇金絲雀釋出:

微服務治理實踐 | 金絲雀釋出

設定新版本号:

微服務治理實踐 | 金絲雀釋出

設定對應的規則(本文使用按比例灰階,90% 的流量進入灰階執行個體):

微服務治理實踐 | 金絲雀釋出

等待金絲雀釋出完畢:

微服務治理實踐 | 金絲雀釋出

金絲雀釋出結果驗證

金絲雀釋出完畢後,再次調用 consumer 對外暴露的位址确認金絲雀是否生效。或者可以在釋出單頁面中檢視灰階監控資料:

微服務治理實踐 | 金絲雀釋出
微服務治理實踐 | 金絲雀釋出

這裡檢視了 3 分鐘監控,89.89% 的流量進入了灰階執行個體(時間越久,比例越準确),基本滿足按照比例的灰階部署。

當結果符合預期并進行全量釋出時,釋出單頁面點選 "下一步" 即可:

微服務治理實踐 | 金絲雀釋出

規則解釋

Spring Cloud 灰階規則目前支援兩種類型:

  • 按比例灰階,可設定 0 - 100 之間的整數
  • 按内容灰階,可以根據參數的内容進行灰階
微服務治理實踐 | 金絲雀釋出

其中 path 表示請求路徑(不填表示支援所有路徑),參數類型支援選擇 Cookie,Header 或 Parameter,條件支援 "=", ">", "<", ">=", "<=", "!=", 白名單, 取模。

條件清單中的每一項支援 "與" 或者 "或" 運算。

舉個例子,這是 consumer 調用 provider 的一個請求:

URL: http://custom-provider/goods/query
Parameter: goodsId=JL110
Header: ENV=Prod           

那麼規則可以這樣設定:

微服務治理實踐 | 金絲雀釋出

Apache Dubbo 灰階規則目前支援兩種類型:

  • 按内容灰階,可以根據接口參數的内容進行灰階

其中條件支援 "=", ">", "<", ">=", "<=", "!=", 白名單, 取模。

舉個例子,定義一個接口如下:

public interface CanaryService {

    String call(String str, int num1,
        Integer num2, String[] strArr, Map<String, String> map,
        List<String> list, User user);

}           

這是 consumer 調用 provider 的參數資訊:

str=str
num1=1
num2=2
strArr=[1, 2, 3]
map={"1":"1", "2", "3"}
list=[0, 1, 2]
User=User{name=name, age=20}           
微服務治理實踐 | 金絲雀釋出

參數 0、1、2 是 String、int 和 Integer 對象,無需設定表達式,直接進行比較。

參數 3 表示一個 String[] 數組,表達式 [0] 表示取第 1 個元素,數組中的第 1 個元素為 1。

參數 4 表示一個 Map<String, String>,表達式 .get("1") 表示取 key 為 "1" 的元素,Map 中 key 為 "1" 的元素是 "1"。

參數 5 表示一個 List 集合,表達式 .get(1)表示取第 2 個元素,數組中的第 2 個元素為 1。

參數 6 表示一個自定義 User 對象(有 name 和 age 兩個屬性),表達式 .getName() 表示調用 getName() 方法,該方法傳回 name 屬性的值,這裡傳遞的是 name。

ECS 叢集使用

上述内容介紹的是在 K8S 叢集下的操作。如若在 ECS 叢集下使用,需要確定至少存在 2 個分組(如下截圖存在 "預設分組" 和 "gray" 這兩個分組):

微服務治理實踐 | 金絲雀釋出

部署應用,選擇金絲雀釋出:

微服務治理實踐 | 金絲雀釋出

上傳新的部署包,設定新版本号,選擇灰階分組:

微服務治理實踐 | 金絲雀釋出

後續規則的操作跟 K8S 叢集一緻。

金絲雀釋出後復原

當金絲雀釋出後,發現有 bug 存在,需要進行應用復原。

釋出單頁面直接點選 "立即復原":

微服務治理實踐 | 金絲雀釋出

金絲雀釋出實作細節

Apache Dubbo 金絲雀底層實作的原理是通過 Java Agent 技術動态添加一個 Router,該 Router 内部使用了 Spring 的表達式 SPEL 進行參數,表達式解析結果判斷是否需要對 Invoker 清單進行修改。如果是正常請求,删除灰階節點;如果是灰階請求,删除正常節點。

Spring Cloud 金絲雀底層的實作細節是對 ILoadBalancer 接口對應的實作類傳回的 Server 清單進行修改。如果是正常請求,删除灰階節點;如果是灰階請求,删除正常節點。

這裡如何判斷哪些節點是灰階節點呢? 這會跟應用釋出流程綁定,當使用 ECS 叢集需要選擇灰階分組,K8S 叢集需要填寫灰階 Pod 個數。這些灰階執行個體或灰階 Pod 啟動的時候會帶上一個灰階标表示自己是一個灰階執行個體或 Pod(Spring Cloud 寫入到 metadata 持久化到注冊中心;Apache Dubbo 寫入到 custom parameter 持久化到注冊中心)。

另外一個問題: 灰階規則如何儲存呢?我們在 Agent 裡通過 Nacos Configuration 的監聽去監聽對應 dataId 的資料變化,這裡的 dataId 跟每個應用 id 綁定(應用 id 也通過跟灰階标一樣的機制持久化到注冊中心)。每次應用釋出都會在 id 對應的 dataId 中寫入灰階規則,Agent 監聽并在記憶體進行修改。

招賢納士

我們 Dubbo / Spring Cloud 商業化團隊正在招人,除了 EDAS,我們還有 ARMS (應用實時監控服務)、MSE(微服務引擎)、ACM(應用配置管理)、SAE(Serverless 應用引擎)等獨立産品。我們在忙什麼?用心打磨這些産品,就是我們的工作。團隊的目标是将阿裡巴巴在服務治理上的最佳實踐通過産品化的形式輸出給阿裡雲上的企業客戶,幫助客戶實作業務永遠線上。

履歷投遞方式:[email protected]

作者資訊:

方劍(花名:洛夜)阿裡雲智能進階開發工程師,Spring Cloud Alibaba PMC,Apache RocketMQ Committer, Nacos Committer。主要負責 Spring Cloud Alibaba 開源項目及微服務商業化内容,目前關注 Spring Ecosystem, 微服務,雲原生等領域。