一、背景互联网产品开发有个非常特别的地方,就是不停的升级,升级,再升级。采用敏捷开发的方式,基本上保持每周或者每两周一次的发布频率,系统升级总是伴随着各种风险,新旧版本兼容的风险,用户使用习惯突然改变而造成用户流失的风险,系统宕机的风险,500错误服务不可用的风险等等。为了避免这些风险,很多产品都采用了灰度发布的策略,其主要思想就是把影响集中到一个点,然后再发散到一个面,出现意外情况后很容易就回退,即使影响也是可控的。任何脱离实际业务的技术工作都是耍流氓,技术需要服务于业务。因此,本文尽量淡化了业务方面的因素,聚焦于技术层面,建议在实际运用中还是要根据各自的业务场景去变化和调整。二、什么是灰度灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。互联网系统,灰度其实就是根据设定的规则将请求路由到我们的灰度版本(灰度机器)上来。比如对于API来说,一般有如下几个需求:特定用户(比如测试帐号)、 特定的App(比如测试app或者合作App)、特定的模块、接口(只有某些接口需要灰度,这种一般是API Container的修改,拿一些不是很重要的API做灰度测试)、特定的机器(某些请求IP转发到灰度机)等。三、灰度的优势1、 在发布过程中降低上线风险2、 降低影响范围,并且范围可控3、 降低对测试的依赖,减少线下自测的数据构造成本4、 特定的请求能够指向特定的服务器,方便集中监控日志,方便跟踪完整的调用链路5、 方便系统流量切入6、 便于随时回滚7、 指定特定人群,方便系统回访,方便产品需求收集,完善产品功能,提升产品质量8、 在无状态的情况下保障用户使用到的版本一致9、 避免宕机给用户带来不好的体验和使用四、目标1、 做到对现有业务系统无侵入性2、 能够发挥以上提到的灰度的优势3、 发布系统的灵活配置4、 发布系统和业务系统的松耦合5、 和网关系统结合,让操作平滑五、功能1、 路由策略管理/配置2、 灰度规则管理3、 开启/关闭开关六、系统设计需要设计的系统分为两种场景,一种是http方式接入,需要借助网关(gate-way)去实现流量的切换,和系统路由;另一种是rpc接入(目前为dubbo),需要借助dubbo提供的负载均衡策略来实现,结合自带的qos(dubbo的在线运维命令)实现服务启动/关闭。【说明】:服务内部执行线程监控待定,sentinel 、 pinpoint or other。1、http方式接入其中分为几个重要的部分:接入层网关,接入客户端请求,根据下发的配置将符合条件的请求转发到新旧系统上.配置管理后台,这个后台可以配置不同的转发策略给接入层网关.稳定和灰度两种处理客户端请求的业务服务器.http请求的入口都落在网关上,网关会根据管控平台(admin dashboard)的配置进行uri的选择。此时请求数据会判断当前应用是否已经开启灰度,再次判断是应用级别的灰度还是服务级别的灰度,然后根据管控平台配置的灰度策略进行灰度,可以支持白名单、权重、ip段、业务域等。管控平台会调用引擎管理执行相应的指令,进行关闭、开启、更新策略和白名单数据等,每次网关重新reload和重启时会从灰度管理系统调用接口读取配置应用的信息,加入缓存。为了提升性能,应用的基本信息、灰度策略、白名单等数据缓存在内存或者类redis这样的缓冲中,灵活的进行缓存数据的更新。实现功能:1、动态路由2、服务动态编排,实现流量的自由切换3、启服/停服4、服务自检2、rpc(dubbo)接入如果直接停机重启rpc service会有什么影响:服务发布时,直接重启Tomcat,导致节点正在处理的请求会受到影响,严重时会有数据异常。服务发布时如果节点正在作为task_tracker运行lts任务,会导致任务失败并retry。服务发布时如果节点正在消费RocketMQ中的消息,会导致消息消费异常,甚至进入retry或dlq队列。服务发布完成后没有即时验证机制,直接暴露给用户,如有异常影响面很广。线上无法同时存在新老版本的服务来用于长时间的验证。竟然有这么多问题,想想就可怕,泪崩~,因此必须想法优雅的实现服务的启停,因此引出dubbo 服务的持续发布:dubbo-consumer实现不同的负载均衡,在负载的时候进行白名单校验和策略选择。系统对灰度管控平台非强制依赖,管控平台出现问题不影响系统正常运行。负载动态路由,阻止后续流量进入,监控服务是否还有执行的线程,加入钩子offline服务或者接口,进行服务升级,自检,启动online,接入负载均衡。由于很多接口都有在Dubbo中进行注册,因此需要有办法能够对其Provider Service接口进行下线或屏蔽,使其不提供服务,即其它服务无法调用它的接口。Service接口下线后,此consumer机器自然无任何流量流入,因此也无流量返回,达到下线consumer机器的目的,然后即可部署代码。官方有提供Dubbo-Admin工具,用于对Dubbo中各APP及其Service接口进行管理,里面自然也包含有实现下线的功能,可以有3种方法:屏蔽,貌似一直没有效果(尴尬);禁用,可以成功禁用;权重调节,可以设置0-100的权重,设置为0时即不提供服务。经过权重调节方案,通过Dubbo-Admin对需要下线机器的APP应用接口权限设置为0。实现的功能:1、缓存负载策略在系统启动的时候要根据系统配置拉取灰度策略,并且保存在内存中,定时获取最新的负载策略,需要提供及时触发的策略更新接口。2、 负载均衡在系统上线之前选择运行时使用的负载均衡进行调用。3、系统配置系统在上线前需要录入管控平台,并且完成相应的配置,在启动的时候作为唯一标识能够拉取相应的配置。4、监控和统计系统在内存中缓存统计信息,定时上传管控平台,监控出现问题不影响系统正常使用(sentinel,or dubbo-amdin模块扩展)。5、qos运维工具系统的启动使用qos,停服采用延时关闭结合jvm钩子。七、检查机制为了平滑发布的顺利进行,检查确认机制不可或缺,即确保Dubbo/Http中的下线都已生效,并且无流量发生,我们从以下两个维度去检查:接口检查,调用Dubbo、Http的API接口,检查业务服务机器状态,是否为已经下线。当然,在做了下线功能的同时,我们也有检查功能和上线功能,可供调用。监控检查,调用监控平台(ELK)的API接口,检查业务服务机器的请求访问数和日志流量是否都已经为0,已经处于下线状态。经过上述改造后,我们新的发布流程如下,基本解决了平滑发布问题,发布时对业务的影响降到了最低;八、停服/启服后小范围验证1.灰度验证–不影响线上用户2.部分实例发布– 导部分流量到新实例(可通过网关路由规则:用户ID取模,区域限制等等)3.全部发布