2016.04.19 丨 壹佰案例
增长黑客口中的灰度发布在技术上是怎么实现的
2016.04.19 丨 壹佰案例
吴浩清:魅族高级开发工程师。曾就职于广州YY、深圳腾讯,现就职珠海魅族科技。主要从事Java服务端开发,对高并发、分布式服务感兴趣。
本文根据msup和魅族联合举办的《第三期魅族技术开放日-架构设计与优化》录音整理原创首发,转载或节选内容前需获授权。
何为灰度
维基百科说“灰度发布是指黑与白之间能够平滑过渡的一种发布方式”,我个人觉得灰度是先让部分人用起来,再让另一部分人用起来,最终达到大家都用这个目的。
两大需求决定魅族广告必须灰度
一、产品侧需求,产品侧主要有以下几个需求:白名单用户,白名单就是一些公司内部员工的白名单,这些用户在请求广告或者其他接口的时候,是不走正常的业务流程的,直接返回某些数据;某些规则用户,比如某些正则匹配的用户,某些用户群体,这也是需要返回特定数据;按照其他业务逻辑,业务链条是复杂,但又是可抽象,有时需要根据业务的链条,返回特定数据;
从事互联网的同学都知道,互联网产品不是一蹴而就,需要不断跟进局部用户反馈并优化,这在海量的互联网产品都有所体现,以上几点就是产品侧的灰度需求。
二、技术侧需求。有了产品侧需求,我们来讨论技术侧需求,对于我们业务来说,既然是广告,肯定有推荐,推荐就是根据你个人的一些用户画像进行精准的数据反馈,这里面就涉及到算法,包括几套算法,他想要验证几套算法是怎样的,从中得出比较好的算法,这个时候就需要推荐广告算法的A/B Test;
还有就是新接口验证;比例放量,避免全线升级引起的潜在故障问题。我们现在新上一些接口,又不想全线升级,因为全线升级可能存在一些问题,我们想升级部分服务进程,然后根据放量的情况来决定接下来的发布,这是我们的技术需求。有了需求接下来看看解决方案。
三、业内解决方案:Nginx+Lua
常规的业内解决方案,Nginx+Lua,lua脚本可以读写缓存数据,它这种能力让Nginx插上了飞翔的翅膀,比如Cache配置了系统的灰度规则,外部请求进来,经过Nginx,灰度数据根据你的请求判断一下逻辑,最终转达到对应的Upstream,也就是最外层的接口。
这种方案也是比较简单粗暴的,但每家公司都有每家公司的技术基础和平台,因为我们是一个小厂商,目前一些工具都不是很完善,运维工具平台缺失,存在沟通、测试成本问题,修改Nginx配置等需要运维同事配合。前端Nginx与逻辑数据交互,增加配置维护成本,这个方案我们最终没有选择。
魅族广告灰度细节
一、历史架构
我们的历史架构是很简单的,通过用户到接入层,再到逻辑服务层,最下面就是资源层,就是这四层,也是业内比较常规的做法。
二、新增抽象层
刚才讲了我们的灰度需求以及历史架构,现在讲讲我们的解决方案,我们的解决方案是新增抽象层,业内有句话是这样的:软件碰到的问题,都可以通过抽象一层来解决(当然,后半句是抽象过多是不好的)。说到抽象层大家都会说,你新增抽象层效率是不是降低,这是必须的,因为你的链路调用过多了,性能肯定就损耗了,但我们考虑到平衡到设计的自由度的问题,我们牺牲了部分性能来换取设计的自由,也与业内空间与时间权衡的问题是一样的。整个设计以平衡效率和自由度为设计原则。
在设计之前要有一个愿景,你的抽象层要做到什么东西,我们抽象层的愿景定了几个点:1、负责抽象,不参与业务,不管你是广告或者说其他的系统,我们都不需要参与业务。2、业务接口变更,抽象层不需升级。3、热加载相关配置数据,你的配置修改不应该重启。4、过载保护、接口质量反馈等,我们应该把业内常规的功能加上去。
三、整合轮子,达成愿景
我们自己的定位是创新型公司,也是小厂商,作为业务方怎么快速达到目的,是小步快跑的方式。
我们自己设计了一个网关层,遵循灰度规则、进行接口级别粒度管理和过载保护等;这个网关层有两个模块在支撑:
一个是RPC服务框架,这是我们公司自研的,我们的服务框架支持接口版本调用。什么是接口版本调用呢?同一个接口,命名为A的接口有两个版本或者是有更多的版本,他也支持High Availability与Load Balance特性,服务注册和服务发现,RPC服务可局部实例升级;
另外配置中心可数据热加载,以上就是我们改造后的架构,很简单,就是多了网关层,意味着我们灰度规则只需要在网关层加入就可以了,同时网关层也是RPC服务的客户端,业务逻辑层变成了RPC服务,之前这里全部是逻辑方面的服务。通用网关集群,与服务发现的Zookeeper交互,所以整个变化就是多了一个网关的东西。
四、魅族广告灰度细节
1、接口设计
我们在接口刚开始设计的时候,尽量设计得大而全,是什么意思呢?要冗余值段,虽然会冗余,比你接下来不断修改好。我们的每个接口设计都是有版本信息和用户信息,为什么要用到版本信息,刚刚说到RPC服务要制定版本,客户端会传一个版本过来;还有就是用户信息,主要在灰度规则的时候用到。在这里可以总结一下,现在很多移动互联网的开发,前端跟后端的接口,我个人觉得,你在接口设计最开始的时候,就应该把这些东西传过来,不管你有没有用到,以后你都会用到。同时我们的接口是无状态的。
2、网关层的灰度顺序
接下来讲一下灰度顺序,抽象出来有三个灰度规则,刚才说到我们的客户端的接口肯定会要有版本信息,首先要有全局规则,适用于白名单;指定用户、匹配正则用户灰度,它到第一个规则找不到,就到第二个规则找,第二个规则找不到,他就走到版本比例灰度,版本比例灰度主要用于什么业务产品,比如我们新上了一个接口,我们想要把历史10%的流量牵到这个新接口,这个时候怎么实现,版本比例灰度就可以用到,适用于放量,比如V1放量20到V2接口。
3、服务注册
这是我们的一个服务细节-服务注册,比如这台机器提供了哪些服务,这里有一个接口,它有两个版本,一个是0,一个是1,这里的0跟1最终会变成第二个版本,就是说网关会调用。服务发现流程主要是这样的:客户端HTTP请求经过网关匹配对应的版本,比如这个规则经过之后,找到是0版本就调用0版本,找到1版本就调用1版本,最终RPC请求后端服务,然后服务执行返回,再从网关返回。
五、灰度流程
这是灰度流程,这个流程是基于我刚才讲的,只是把它图形化而已。这是比较简单的,也就是网关层跟RPC服务集群是怎样的流程,用户有一个请求过来,网关层从配置中心里面获取这个请求需要的版本,根据参数个数、参数类型,并获取参数内容,再根据灰度规则获取对应接口版本,组装成RPC。整体来说我们的方式是比较简单粗暴的。能用简单方式解决技术的问题,就尽量不要把系统设计复杂化。
Q&A
:接口通过版本的方式去管理确实比较利于灰度,但比如灰度完了,可能前面积累了很多版本,下一次又增加一个版本,然后又继续增加,前面的版本有没有一个什么管理过程把它下掉呢?
:你说的这个问题,我们先看一下魅族广告灰度细节,我们刚开始设计的时候,灰度逻辑不仅仅有这三个,刚开始设计的时候已经达到了五六个规则,后来不断地抽象发现有些东西是可以合并的,所以简单来说我们现在只有两个,全局规则是前提,然后是指定用户/匹配正则用户灰度,然后是版本比例灰度,适用于放量。随着接口不断增多,你怎么维护这些东西,目前我们需要管理后台,但因为我们是不断的迭代过程,现在我们的复杂程度没有到达你说的那个程度,我们现在也只有十几个版本而已,还没有达到上百、上千的版本。至于说吧服务下线,只要客户端没有请求某个版本接口了,后台把对应的接口服务下线即可。