Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

Stella981
• 阅读 471

微信公众号:[中间件兴趣圈]
作者简介:《RocketMQ技术内幕》作者

方案背景

背景:基于Dubbo服务的治理,是否可以支持业务级别的灰度发布、是否基于业务参数的路由转发。例如以GIS为例,当发布一个新版本时,是否可以以按照解析地址或合作伙伴来区分,版本发布之初,只希望地址为:广东省的解析请求发送到新版本,而其他的地址请求还是使用旧版;或者根据合作伙伴例如UCP(优享寄)的请求转发到新版本服务器,其他合作伙伴还是转发到旧版,实现业务级别的灰度发布,控制新版本的影响范围。例如OMS系统,可以根据合作伙伴,将重量级客户的请求转发到单独的服务器集群,确保其高可用。
 本文将对上述议题结合Dubbo提供的功能,提出设计方案。

方案理论基础

Dubbo的服务调用原理图:

Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

 客户端在发起RPC服务调用之前,在客户端首先从服务器列表中选择一个服务调用者,包含如下关键角色:
1、Directory
服务的动态发现,通常基于注册中心进行服务的动态注册与发现,其具体实现类为RegistryDirectory。

2、Router
路由实现,其含义是根据Directory发现的所有服务提供者列表中,进行路由选择,也就是根据一定的路由规则选择合适的服务提供者,为Directory发现的服务提供者列表子集,可以基于Condition或脚本(默认为JS脚本,其实现类为ScriptRouter)。

3、LoadBalance
 负载均衡机制,其作用主要是根据负载均衡算法(随机、轮询)等算法,从(Directory-->Router)中返回的服务提供者列表中选择一个服务提供者,进行本次的RPC服务调用。

4、Cluster
集群(容错机制),就是当从服务提供者列表中按照负载均衡算法选择一个服务提供者,进行RPC服务调用后,发送了异常后的策略,例如failover(重试)、failfast(快速失败)等。
 
服务的灰度发布,其目标是希望根据请求,某些请求走新版本服务器,某些请求走旧版本服务器,其本质就是路由机制,即通过一定的条件来缩小服务的服务提供者列表,正好与Dubbo的Router相吻合。

有关于Dubbo的Router机制,请参考官方文档第【46、47、48】页,如果想从源码的角度了解其实现机制,请参考 Dubbo路由机制概述
 
有了理论支持,下文将根据上述理论进行实战。

方案具体实现示例

本示例代码需要完成的任务是,对DemoService#createUser服务,其用户机构ID(orgId)为1的走新版本(当前服务提取者列表的最后一台服务器),其他的请求走所有的服务器(除最后一台服务器)。

Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

由于是需要基于请求参数,本文给出基于JS脚本的路由机制,首先,当前版本的dubbo-admin可以后台页面维护基于条件表达式的路由规则,其界面如下:

Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

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 * @returns10 */11function demoService_createUser_router(invokers, invocation, context) {12    if(invokers == null || invokers.size() < 1) {13        return invokers;14    }1516    if(!"createUser".equals(invocation.getMethodName())) { // 如果方法不匹配,默认无条件通过该路由规则17        return invokers;18    }1920    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    }2627    var invArguments = invocation.getArguments();28    if(invArguments == null || invArguments.length == 0) { // 如果参数为空,无法根据参数进行路由选择29        return availableInvokers; 30    }3132    // 获取需要进行路由的参数,这里使用第一个参数 ,这里各自根据各自的业务 进行获取,本实例默认使用第一个参数33    var firstArgument = invArguments[0];34    var orgId = firstArgument == null ? "" : firstArgument.getOrgId();353637    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.Demo11                Service?category=routers&dynamic=false&enabled=true&fo12                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官方微信公众号

Dubbo服务治理之灰度发布方案(版本发布控制影响范围)

本文分享自微信公众号 - 中间件兴趣圈(dingwpmz_zjj)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java中比较两个时间的差值
项目背景1.某篇文稿的发布时间是publishDate,例如:2020072118:00:41。2.现要求判断该篇文稿的发布时间是否在近30天之内。publicstaticlongdayDiff(DatecurrentDate,DatepublishDate){LongcurrentTimecurrentDat
基于Istio的灰度发布架构方案实践之路
灰度发布,是指能够平滑过渡的一种发布方式。尤其是对于toB业务和SAAS类平台,很多情况需要根据租户或用户维度进行灰度控制,实现业务上的A/Best功能。尽管几经迭代,但仍存在系统入侵性强、新版本接口异常等问题。因此,探索了一条基于Istio的服务流量治理方案下的灵活可配置的灰度发布方案。
Stella981 Stella981
3年前
Nepxion Discovery 5.5.0 发布
!(https://oscimg.oschina.net/oscnet/f81c043194ef4732880459d00c1a720e.png)发布日志功能更新:增加基于Opentracing调用链的支持,目前支持UberJaeger,实现在SpringCloudGateway、Zuul和服务上的灰度
Stella981 Stella981
3年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这