kaitezhan / GraySystem

灰度系统(基于dubbo、spring扩展实现的接入层灰度、服务层灰度、mq灰度、外部调用灰度,支持多套灰度环境)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

灰度系统

概要及背景

为了保证线上业务质量,因此做了一套后台灰度系统。通过简易的配置即可将系统进行灰度。该系统已在线上生产环境正式运行1年。 基于Dubbo、Spring扩展实现。 在获得公司准许的情况下,现把灰度系统的代码抽离出来。

功能点

  • 可以基于单个服务灰度(也可以整体控制灰度)
  • 基于接口灰度
  • 外部依赖接口的灰度
  • mq灰度
  • 接入层与服务之间的灰度调用
  • 服务于服务之间的灰度调用
  • 支持多套灰度环境
  • 容灾:灰度/正式服务不可用,降级调用正式/灰度服务

系统组成

整体分为:灰度配置服务、代理服务、灰度组件(核心) Snip20180920_1

使用方法:

服务引入灰度配置

1、创建 META-INF.dubbo文件夹

2、配置filter
(1)创建 com.alibaba.dubbo.rpc.Filter文件 内容是 grayFilter=com.facishare.wechat.union.common.component.DubboGrayFilter 如果需要自定义filter,可以继承com.facishare.wechat.union.common.component.DubboGrayFilter, 然后在等号后面写上实现类

3、配置loadBalance (1)创建 com.alibaba.dubbo.rpc.cluster.LoadBalance文件 内容是 grayLoadBalance=com.facishare.xxx.xxx.xxxLoadBalance 普通项目只要进行步骤(1)就可以了

(2)在web、fcp项目中,需要创建子类xxxLoadBalance,并且把实现类路径写在等号后面, 主要是获取fsEa

4、spring配置文件中添加:
<import resource="classpath*:/spring/wechat-union-common.xml"/>

PS:简单来说,除了web接入层的项目,其他项目只要
(1)创建com.alibaba.dubbo.rpc.Filter、com.alibaba.dubbo.rpc.cluster.LoadBalance文件 (2)导入<import resource="classpath*:/spring/wechat-union-common.xml"/>

机器准备

PS: 如果部署有问题,请致邮件: 296947440@qq.com 除了上班时间基本在线

灰度机器2台(如果外部依赖的都是旧接口,1台就好了),正式机器1台 注意灰度系统是支持多套灰度环境的,一套灰度环境建议使用2台机器(容灾)

灰度机器,需要部署2台。正常机器一台即可(之所以灰度机器需要两台以上,是因为只部署一台的话,那么新的接口service只有1个invoker, 因此不经过loadBalance,因此没有给group赋值,因此去provider侧寻找invoker的时候,会找不到)

后台管理灰度配置

配置灰度环境

配置灰度环境之前,需要部署启动gray-config-admin项目

image-20190916163851104 如图,配置了2个灰度环境,并且含有各自环境的灰度名单

配置灰度应用

image-20190916164009751 把灰度服务配置到灰度环境中,一个灰度服务可以在多个灰度环境中,一个灰度服务的某台机器只能在1个灰度环境中。

启动服务

配置好灰度配置后,就可以启动服务了,生成灰度环境了。剩下的就是动态路由调用。


实现原理

划分灰度环境

在服务启动时,根据该服务的灰度机器列表,判断该服务下这个台机器是否需要灰度,如果是,则设置为灰度环境配置(该服务设置为灰度group)。 通过使用GrayBeanPostProcessor初始化之后,通过group的来划分,dubbo服务被划分灰度环境、正式环境。这里需要注意的是,该灰度系统的核心之一就是通过group进行灰度环境的划分。

具体流程如图: Snip20180920_1

动态路由

通过上面的步骤,已经将服务划分为灰度环境、正式环境。接下来就是利用dubbo的loadBalance、Filter扩展,达到动态调用灰度/正式服务的效果。调用的顺序为loadBalance——》filter。

具体要怎么做呢? 在consumer侧,我们为了在LoadBalance中获取到所有provder对应的invoker,所以设置group为“*”。然后我们根据首先根据请求的身份信息,判断该用户走灰度还是正式环境,然后调用灰度/正式服务。 在provider侧,所有invoker都被存储在map中,等待consumer进行获取调用,并且key的里面包含了group,所以consume进行调用的时候,必须要携带group,才能把group作为key的一部分,去正常的获取到invoker。

如果consumer调用的时候不携带group,那么dubbo默认会把ConsumerConfig的group属性值当做参数传递给provider方。而在在provider侧,会从一个Map获取接口的exporter,key类似于 */com.xxxx.xxService.queryMethod这种格式,因此,这样子是拿不到invoker的。

Snip20180920_1 Snip20180920_1

另外,对于灰度服务的调用,我们会将“”替换成灰度的group,这样子能正常调用成功。但是对于正常服务的调用,是没有group的,因此dubbo直接把group=““传递给provider,调用失败。

因此我们做了一个兼容性的处理,通过provider侧的filter去把非灰度group(也就是”*“)设置为空,那么非灰度服务也能正常调用了。

通过查看源代码,在provider侧获取exporter进行调用时,使用invocation获取group值,利用该值组成key,因此,如果在consumer消费之前,可以通过invocation设置group的值(调用灰度服务,则设置为对应的灰度group;调用正式服务,则设置为”“,因为”“不会被添加到key中),就可以获取得到exporter,从而达到调用灰度/正式服务的效果

Snip20180920_5

代理层实现外部调用灰度

说明:外部服务调用interface.method1的时候,调用proxy项目的interface.method1,然后获取用户信息(fsEa、wxAppId、appId...), 从而判断是走灰度服务,还是正常服务,选择完毕,调用project的同名服务 Snip20180920_1

mq灰度处理

每一个服务定时拉取灰度配置,判读该服务所处的机器是否灰度机器。 灰度机器则初始化mq,可以处理mq消息;正式机器则关闭mq,不处理mq消息。

About

灰度系统(基于dubbo、spring扩展实现的接入层灰度、服务层灰度、mq灰度、外部调用灰度,支持多套灰度环境)


Languages

Language:Java 87.8%Language:CSS 8.9%Language:JavaScript 3.3%