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

1、方案背景
   背景:基于Dubbo服务的治理,是否可以支持业务级别的灰度发布、是否基于业务参数的路由转发。例如以GIS为例,当发布一个新版本时,是否可以以按照解析地址或合作伙伴来区分,版本发布之初,只希望地址为:广东省的解析请求发送到新版本,而其他的地址请求还是使用旧版;或者根据合作伙伴例如UCP(优享寄)的请求转发到新版本服务器,其他合作伙伴还是转发到旧版,达成业务级别的灰度发布,控制新版本的影响范围。例如OMS系统,可以根据合作伙伴,将重量级客户的请求转发到单独的服务器集群,确保其高可用。
   本文将对上述议题结合Dubbo提供的功能,提出设计方案。
2、方案理论基础
   Dubbo的服务调用原理图:
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第1张图片
   客户端在发起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】页,如果想从源码的角度了解其实现机制,请参考博文:https://blog.csdn.net/prestigeding/article/details/80848594
   有了理论支持,下文将根据上述理论进行实战。
3、方案具体实现示例
   本示例代码需要完成的任务是,对DemoService#createUser服务,其用户机构ID(orgId)为1的走新版本(当前服务提取者列表的最后一台服务器),其他的请求走所有的服务器(除最后一台服务器)。
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第2张图片
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第3张图片
   由于是需要基于请求参数,本文给出基于JS脚本的路由机制,首先,当前版本的dubbo-admin可以后台页面维护基于条件表达式的路由规则,其界面如下:
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第4张图片
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第5张图片
   备注:并且当前dubbo-admin版本,并不支持基于JS表达式的路由规则,如果手动建立基于表达式的路由规则,其页面将无法列出路由表达式,其界面如下:
Dubbo服务治理之灰度发布方案(版本发布控制影响范围)_第6张图片
   3.1 JS脚本
   各个项目,各个服务需要根据自身的需求,定义如下脚本:

/**
 * DemoService router,针对不同的方法,可能需要各自提供,主要是参数的获取,不同的过滤规则
 * 针对参数进行路由过滤
 * 
 * 本示例针对 DemoSerivce# ResponseResult createUser(User user) 方法,根据user的orgId进行路由选择
 * @param invokers
 * @param invocation
 * @param context
 * @returns
 */
function demoService_createUser_router(invokers, invocation, context) {
	if(invokers == null || invokers.size() < 1) {
		return invokers;
	}
	
	if(!"createUser".equals(invocation.getMethodName())) { // 如果方法不匹配,默认无条件通过该路由规则
		return invokers;
	}
	
	var availableInvokers = new java.util.ArrayList(invokers.size());
	for (var i=0;i

   3.2 向注册中心注册JS脚本路由规则
   上文已经说明,目前的dubbo-admin不支持在界面上注册路由规则,现给出基于JAVA代码来编写注册程序:

public static void main(String[] args) throws Exception{
	URL registryUrl = URL.valueOf("zookeeper://127.0.0.1:2181");
    ZookeeperRegistryFactory zookeeperRegistryFactory = new 
                       ZookeeperRegistryFactory();
   zookeeperRegistryFactory.setZookeeperTransporter(new 
        CuratorZookeeperTransporter());
   Registry zookeeperRegistry = (ZookeeperRegistry) 
             zookeeperRegistryFactory.createRegistry(registryUrl);
   URL routerURL = 
          URL.valueOf("script://0.0.0.0/com.alibaba.dubbo.demo.Demo
                Service?category=routers&dynamic=false&enabled=true&fo
                rce=false&name=demoService_createUser_router&priority=
          0&runtime=true");
   routerURL = routerURL.addParameter("rule", 
   URL.encode(get_demoService_createUser_router()));
   zookeeperRegistry.register(routerURL);     // 注册
   // zookeeperRegistry.unregister(routerURL); // 取消注册
}

   一旦运行上述代码,将会动态注册URL,服务提供者无需重启,下次服务调用后会自动生效(其背后原理是基于注册中心的动态发现)。
上述示例代码,我已经在本地环境,已能成功运行,并达到预期效果,公司项目需要根据自身的特点,特别服务方法的参数(例如合作伙伴ID的获取方式),以及路由需求来定制编写其路由脚本(js脚本)。
   3.3 总结
上述展示了Dubbo服务基于业务灰度发布的方案,以及基于合作伙伴的服务隔离机制(根据服务调用业务参数来决定服务调用者的筛选)。主要是展示了基于脚步的路由规则,其条件表达式的路由规则请参考其Demo,其核心理论支持是Dubbo提供的Router,在进行负载均衡前,根据路由规则对服务提供者列表进行筛选。


欢迎加笔者微信号(dingwpmz),加群探讨,笔者优质专栏目录:
1、源码分析RocketMQ专栏(40篇+)
2、源码分析Sentinel专栏(12篇+)
3、源码分析Dubbo专栏(28篇+)
4、源码分析Mybatis专栏
5、源码分析Netty专栏(18篇+)
6、源码分析JUC专栏
7、源码分析Elasticjob专栏
8、Elasticsearch专栏(20篇+)
9、源码分析MyCat专栏

你可能感兴趣的:(dubbo,源码分析Dubbo专栏)