dubbo蓝绿
目前做devops项目,去年提供了蓝绿发布功能,因此分享下,首先介绍下几种常见的部署方式,最后介绍下蓝绿发布的实现
1.常见部署方案介绍
1.1.蓝绿发布
蓝绿部署,是指同时运行两个版本的应用,蓝绿部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上。但
是蓝绿部署要求在升级过程中,同时运行两套程序,对硬件的要求就是日常所需的二倍,比如日常运行时,需要10台服务器支撑业务,那么使用蓝绿部署,你就需
要购置二十台服务器。蓝绿发布本质就是使用硬件冗余的方式,实现发布过程中的0 downtime,在新版本有问题后,可以通过一键回滚到旧版本。
1.2.A/B Testing
A/B 测试跟蓝绿部署完全是两码事。
A/B 测试是用来测试应用功能表现的方法,例如可用性、受欢迎程度、可见性等等。 A/B 测试通常用在应用的前端上,不过当然需要后端来支持。
A/B 测试与蓝绿部署的区别在于, A/B 测试目的在于通过科学的实验设计、采样样本代表性、流量分割与小流量测试等方式来获得具有代表性的实验结论,并确信
该结论在推广到全部流量可信;蓝绿部署的目的是安全稳定地发布新版本应用,并在必要时回滚。
A/B 测试和蓝绿部署可以同时使用。
1.3.灰度发布
灰度发布是在原有版本可用的情况下,同时部署一个新版本应用作为“金丝雀”(金丝雀对瓦斯极敏感,矿井工人携带金丝雀,以便及时发发现危险),测试新版本
的性能和表现,以保障整体系统稳定的情况下,尽早发现、调整问题。
灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。
1.4.滚动发布
滚动发布能够解决掉蓝绿部署时对硬件要求增倍的问题。
所谓滚动升级,就是在升级过程中,并不一下子启动所有新版本,是先启动一台新版本,再停止一台老版本,然后再启动一台新版本,再停止一台老版本,直到升级完成,这样的话,如果日常需要10台服务器,那么升级过程中也就只需要11台就行了。
但是滚动升级有一个问题,在开始滚动升级后,流量会直接流向已经启动起来的新版本,但是这个时候,新版本是不一定可用的,比如需要进一步的测试才能确认。那么在滚动升级期间,整个系统就处于非常不稳定的状态,如果发现了问题,也比较难以确定是新版本还是老版本造成的问题。
为了解决这个问题,我们需要为滚动升级实现流量控制能力。
目前容器部署通常使用滚动发布,旧版本依然提供服务,直至新版本服务完全启动。
1.5.小结
灰度发布主要在于业务方,可以评估一下不同版本客户的反馈效果来决定是否发布。
蓝绿发布和滚动发布的侧重点就是发布。
2.dubbo蓝绿发布的实现
dubbo蓝绿可以通过两种方式实现,使用tag路由或者dubbo的路由规则,下面分别介绍下优缺点
2.1.tag标签路由实现蓝绿
dubbo的标签路由使用很方便,启动的服务直接加上-Ddubbo.provider.tag=blue/green,这样就实现了蓝绿的流量隔离。
使用蓝绿之前的流量请求结构
使用蓝绿后
dubbo服务使用tag标签进行流量隔离,具体要访问蓝绿哪个服务,由web服务控制。
使用tag标签路由有个问题,就是调用别人的服务需要和自己的tag相同,或者对方服务不存在tag。如果其它被调用服务也使用了tag,那么就会找不到服务。因此使用tag路由的,还需要准备套没有tag的服务便于调别人服务。这也是个麻烦点,实际上,功能并没有路由规则强大,但是胜在简单。
2.2.路由规则实现蓝绿
比如我们的服务架构如下图
用户通过网关(dubbo泛化)来访问我们的dubbo服务,我们的代码都是写在dubbo服务内。现在想通过蓝绿,实现下面的效果
其中dubbo服务蓝绿对应线上的新旧版本。
做法是:对于蓝绿应用启动时候分别追加自定义启动参数-Ddubbo.provider.parameters.blueGreenTag=blue/green,那么线上就存在了两套服务,分别是蓝绿服务。那么如何进行蓝绿切换呢?比如我们的流量接入都是由网关控制,网关使用的dubbo泛化,网关提供个蓝绿切换接口,在服务发布后,通过devops平台点击蓝绿切换,用户就可以选择由蓝切换到绿,由绿切换到蓝。具体的实现就是dubbo的路由规则了。即在这个dubbo应用下的的所有服务的routers节点创建/修改一天route地址,而由于网关会监听对应服务的routers节点,因此zk通知dubbo consumer端(即网关)refreshinvoker,从而网关就会调用对应的蓝/绿服务。
这里有两个疑问:
1.自定义的启动参数-Ddubbo.provider.parameters.blueGreenTag=blue/green是如何加载的?
2.为什么我通过devops平台点击切蓝/切绿按钮后,网关就只会调用蓝/绿服务?
解答:
1.自定义的启动参数-Ddubbo.provider.parameters.blueGreenTag=blue/green,在dubbo启动过程中,会自动保存到ProviderConfig.parameters集合(因为会自动把dubbo.provider开头参数绑定到ProviderConfig的对应属性上),其中key就是blueGreenTag,value就是blue/green,这样在服务暴露时候,在doExportUrlsFor1Protocol操作内appendParameters(map, provider, Constants.DEFAULT_KEY);
,就会把ProviderConfig.parameters集合参数保存到map上,从而注册到zk上的provider url上就会携带上自定义的参数,例子如下图
dubbo://192.168.5.1:20880/org.pangu.api.ProductService
anyhost=true
application=pangu-service-provider
bean.name=ServiceBean:org.pangu.api.ProductService
default.blueGreenTag=green
default.tps=1000
default.tps.interval=2000
dubbo=2.0.2
generic=false
interface=org.pangu.api.ProductService
methods=findProduct,selectProduct
pid=10876
side=provider
timestamp=1627397851153
可以看到自定义的启动参数default.blueGreenTag=green,注意:默认会增加default开头
这里要注意的是AbstractMethodConfig.parameters,是dubbo提供的用于自定义参数,会追加注册的url上。
比如我线上是蓝服务,现在发布新版本,发布到绿服务上,绿服务启动成功后,但是实际网关调用的还是蓝服务,因此就需要进行流量切换了
2.通过devops平台点击切蓝/切绿按钮后,会去调用网关的接口,网关根据上送的应用名(dubbo应用名),查找到当前应用下所有的服务(网关会维护所有的dubbo服务名),从而修改每个服务下的router协议,修改zk上router url的例子如下
/dubbo/${interface}/routers/route://0.0.0.0/${interface}?category=routers&dynamic=false&enabled=true&force=false&name=blueGreenRule_${ruleSuffix}&priority=0&router=condition&rule=consumer.methods=*+=>+provider.default.blueGreenTag=${tag}&runtime=false&type=javascript
//ruleSuffix是蓝绿标识+group+version,比如blue_zzzGroup_1.0.0
//tag表示blue/green
从这个具体的url可见,router url的rule是consumer.methods=*+=>+provider.default.blueGreenTag=${tag}
,表示是消费端所有的方法,都去请求服务端携带蓝/绿标识的服务。
实际上是router url被修改后,zk通知网关(dubbo consumer),网关从而refeshInvoker,然后根据ConditionRouter进行路由筛选provider端default.blueGreenTag=green的服务(在toMethodInvokers内),从而最终缓存到RegistryDirectory的服务都是green服务。
说完了dubbo服务的流量切换,还有外部流量的接入,即web服务的流量切换,这里使用的是k8s提供的Ingress,扮演着 “智能路由” 或者集群入口的角色,本质就是个nginx,使用lua脚本进行web流量切换。这个后续再进行深入了解。