Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)

微信公衆號:[中間件興趣圈]
做者簡介:《RocketMQ技術內幕》做者java

方案背景

背景:基於Dubbo服務的治理,是否能夠支持業務級別的灰度發佈、是否基於業務參數的路由轉發。例如以GIS爲例,當發佈一個新版本時,是否能夠以按照解析地址或合做夥伴來區分,版本發佈之初,只但願地址爲:廣東省的解析請求發送到新版本,而其餘的地址請求仍是使用舊版;或者根據合做夥伴例如UCP(優享寄)的請求轉發到新版本服務器,其餘合做夥伴仍是轉發到舊版,實現業務級別的灰度發佈,控制新版本的影響範圍。例如OMS系統,能夠根據合做夥伴,將重量級客戶的請求轉發到單獨的服務器集羣,確保其高可用。
本文將對上述議題結合Dubbo提供的功能,提出設計方案。算法

方案理論基礎

Dubbo的服務調用原理圖:服務器

Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)

客戶端在發起RPC服務調用以前,在客戶端首先從服務器列表中選擇一個服務調用者,包含以下關鍵角色:
一、Directory
服務的動態發現,一般基於註冊中心進行服務的動態註冊與發現,其具體實現類爲RegistryDirectory。微信

二、Router
路由實現,其含義是根據Directory發現的全部服務提供者列表中,進行路由選擇,也就是根據必定的路由規則選擇合適的服務提供者,爲Directory發現的服務提供者列表子集,能夠基於Condition或腳本(默認爲JS腳本,其實現類爲ScriptRouter)。負載均衡

三、LoadBalance
負載均衡機制,其做用主要是根據負載均衡算法(隨機、輪詢)等算法,從(Directory-->Router)中返回的服務提供者列表中選擇一個服務提供者,進行本次的RPC服務調用。運維

四、Cluster
集羣(容錯機制),就是當從服務提供者列表中按照負載均衡算法選擇一個服務提供者,進行RPC服務調用後,發送了異常後的策略,例如failover(重試)、failfast(快速失敗)等。ide

服務的灰度發佈,其目標是但願根據請求,某些請求走新版本服務器,某些請求走舊版本服務器,其本質就是路由機制,即經過必定的條件來縮小服務的服務提供者列表,正好與Dubbo的Router相吻合。設計

有關於Dubbo的Router機制,請參考官方文檔第【4六、4七、48】頁,若是想從源碼的角度瞭解其實現機制,請參考Dubbo路由機制概述3d

有了理論支持,下文將根據上述理論進行實戰。code

方案具體實現示例

本示例代碼須要完成的任務是,對DemoService#createUser服務,其用戶機構ID(orgId)爲1的走新版本(當前服務提取者列表的最後一臺服務器),其餘的請求走全部的服務器(除最後一臺服務器)。

Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)
Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)
因爲是須要基於請求參數,本文給出基於JS腳本的路由機制,首先,當前版本的dubbo-admin能夠後臺頁面維護基於條件表達式的路由規則,其界面以下:
Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)

備註:而且當前dubbo-admin版本,並不支持基於JS表達式的路由規則,若是手動創建基於表達式的路由規則,其頁面將沒法列出路由表達式,其界面以下:
Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)

JS腳本

各個項目,各個服務須要根據自身的需求,定義以下腳本:

1/**
 2 * DemoService router,針對不一樣的方法,可能須要各自提供,主要是參數的獲取,不一樣的過濾規則
 3 * 針對參數進行路由過濾
 4 * 
 5 * 本示例針對 DemoSerivce# ResponseResult createUser(User user) 方法,根據user的orgId進行路由選擇
 6 * @param invokers
 7 * @param invocation
 8 * @param context
 9 * @returns
10 */
11function demoService_createUser_router(invokers, invocation, context) {
12    if(invokers == null || invokers.size() < 1) {
13        return invokers;
14    }
15
16    if(!"createUser".equals(invocation.getMethodName())) { // 若是方法不匹配,默認無條件經過該路由規則
17        return invokers;
18    }
19
20    var availableInvokers = new java.util.ArrayList(invokers.size());
21    for (var i=0;i<invokers.size(); i++) {    // 先選擇可用的服務提供者列表
22        if(invokers.get(i).isAvailable()) {
23            availableInvokers.add(invokers.get(i));
24        }
25    }
26
27    var invArguments = invocation.getArguments();
28    if(invArguments == null || invArguments.length == 0) { // 若是參數爲空,沒法根據參數進行路由選擇
29        return availableInvokers; 
30    }
31
32    // 獲取須要進行路由的參數,這裏使用第一個參數 ,這裏各自根據各自的業務 進行獲取,本實例默認使用第一個參數
33    var firstArgument = invArguments[0];
34    var orgId = firstArgument == null ? "" : firstArgument.getOrgId();
35
36
37    if(orgId == 1 || orgId == "1") { // 若是orgId == 1 ,只走最後一個節點,其他的走其餘節點
38        var selectInvokers = new java.util.ArrayList(1);
39        selectInvokers.add(availableInvokers.get(availableInvokers.size()-1));
40        return selectInvokers;
41    } else {
42        var selectInvokers = new java.util.ArrayList(availableInvokers.size()-1);
43        for(var i=0;i<availableInvokers.size()-1; i++) {
44            selectInvokers.add(availableInvokers.get(i));
45        }
46        return selectInvokers;
47    }
48}

向註冊中心註冊JS腳本路由規則

上文已經說明,目前的dubbo-admin不支持在界面上註冊路由規則,現給出基於JAVA代碼來編寫註冊程序:

1public static void main(String[] args) throws Exception{
 2    URL registryUrl = URL.valueOf("zookeeper://127.0.0.1:2181");
 3    ZookeeperRegistryFactory zookeeperRegistryFactory = new 
 4                       ZookeeperRegistryFactory();
 5   zookeeperRegistryFactory.setZookeeperTransporter(new 
 6        CuratorZookeeperTransporter());
 7   Registry zookeeperRegistry = (ZookeeperRegistry) 
 8             zookeeperRegistryFactory.createRegistry(registryUrl);
 9   URL routerURL = 
10          URL.valueOf("script://0.0.0.0/com.alibaba.dubbo.demo.Demo
11                Service?category=routers&dynamic=false&enabled=true&fo
12                rce=false&name=demoService_createUser_router&priority=
13          0&runtime=true");
14   routerURL = routerURL.addParameter("rule", 
15   URL.encode(get_demoService_createUser_router()));
16   zookeeperRegistry.register(routerURL);     // 註冊
17   // zookeeperRegistry.unregister(routerURL); // 取消註冊
18}

一旦運行上述代碼,將會動態註冊URL,服務提供者無需重啓,下次服務調用後會自動生效(其背後原理是基於註冊中心的動態發現)。

上述示例代碼,我已經在本地環境,已能成功運行,並達到預期效果,公司項目須要根據自身的特色,特別服務方法的參數(例如合做夥伴ID的獲取方式),以及路由需求來定製編寫其路由腳本(js腳本)。

總結

上述展現了Dubbo服務基於業務灰度發佈的方案,以及基於合做夥伴的服務隔離機制(根據服務調用業務參數來決定服務調用者的篩選)。主要是展現了基於腳步的路由規則,其條件表達式的路由規則請參考其Demo,其核心理論支持是Dubbo提供的Router,在進行負載均衡前,根據路由規則對服務提供者列表進行篩選。

最後說明一下:本方案主要展現基於腳本的路由選擇策略,一般在實際使用過程當中基於條件路由較多,例如基於消費者IP進行條件選擇。

更多文章請關注微信公衆號:
Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)

廣告:做者的新書《RocketMQ技術內幕》已上市
Dubbo服務治理之灰度發佈方案(版本發佈控制影響範圍)
《RocketMQ技術內幕》已出版上市,目前可在主流購物平臺(京東、天貓等)購買,本書從源碼角度深度分析了RocketMQ NameServer、消息發送、消息存儲、消息消費、消息過濾、主從同步HA、事務消息;在實戰篇重點介紹了RocketMQ運維管理界面與當前支持的39個運維命令;並在附錄部分羅列了RocketMQ幾乎全部的配置參數。本書獲得了RocketMQ創始人、阿里巴巴Messaging開源技術負責人、Linux OpenMessaging 主席的高度承認並做序推薦。目前是國內第一本成體系剖析RocketMQ的書籍。
新書7折優惠!7折優惠!7折優惠!

推薦關注微信公衆號:RocketMQ官方微信公衆號

相關文章
相關標籤/搜索