将某个功能灰度发布(逐渐放量)给特定线上人群,避免新功能全量上线带来的风险。javascript
上面的图能够经过两个方面来理解:css
举个简单的例子:将http请求cookie中含有test=1字段的请求都转发到灰度代码的机房;
上面经过经过配置特定Nginx规则的方法来达到产品灰度的方法虽然能够知足必定业务量的需求,可是他也有不少的缺点:html
那么有没有更好的方法来作灰度发布呢?固然是有的,A/B测试就可以弥补上面经过Nginx规则来作灰度的缺点。前端
将线上一部分真实人群流量随机拆分红多个组,对每一个分组的人群应用不一样策略或功能,经过计算每组人群的业务指标(转化率、成交率等)来衡量策略或功能的实际效果。java
咱们经过下面的这张图简单的了解下A/B测试的原理:node
由上图咱们能够知道A/B和传统的灰度方法的区别:webpack
传统的灰度是经过Nginx分发流量到服务器,A/B测试是经过业务代码区分流量访问不一样的代码块。nginx
那么A/B测试的优缺点是什么呢?git
优势:web
缺点:
if...else
分支语句。可是这样还好,由于根据SDK的规范来书写代码,仍是很好管理的。前端跟后端很大的区别就是直接面对用户,就算很简单的修改一次按钮的颜色就须要一次上线。这种操做对用户是可感知的。
现代前端有个特色就是脱离了后端模板引擎的渲染,大多数是使用React、Vue这种MVVM框架的前端(浏览器)渲染。这种状况下后端其实仅仅是给用户提供一个空的html文件(工做中常常称做为壳)。大多数业务代码开发完之后都是做为静态文件上线到服务器,通过用户访问后缓存到CDN节点上的。并且这个过程大多数是增量上线的。
其实咱们每次上线完以后服务器上缓存的html文件就包含不一样的版本信息。若是咱们把这些版本信息管理起来,而且经过特定的手段(对用户请求应用A/B测试)就能够完成前端不一样版本的灰度发布。
咱们能够观察下Webpack或者是其它打包工具打包后的html文件。每次外联的静态文件都包含不一样的hash戳。这些外链的文件又都是增量缓存到服务其上的。
index.html (咱们页面的“壳”)
一些 xxx.js文件 (渲染页面+页面的业务逻辑)
xxx.css 文件 (控制页面显示样式)
大概就是下面的这个样子
基于以上的特色,咱们能不能尽可能减小对业务代码侵入,而能够覆盖业务改动较大的需求进行灰度或者是A/B测试呢?
看下下面的这个这个请求的图:
每次咱们打包编译完以后,就将相关的css文件和js文件信息保存到本地的一个json文件中。这些信息的key能够是咱们的git的tag信息(主要来描述本次发版信息包含的功能等)。
基本上json
文件包含的信息以下:
const version = { // 能够描述本次的上线内容/ 或者是git tag 'tag1': { 'css': 'xxxxxxx.css', 'app': 'app_xxx.js', 'ventor': 'ver_xxx.js' } }
这里仅仅是一个简单的demo示例,可使用Nodejs写文件的特性直接将文件版本号写入到index.html返回给前端浏览器
Nodejs服务的特色是每次更新完代码须要重启以后才能生效。每次上完线重启服务就会先检查本地代码根目录下的这个json文件。看下这个其中包含的tag是否在DB中存储,若是有存储就不作操做,若是没有就将它存储DB作持久化。
上面图上面的Apollo就是用来配置那些用户访问新功能的平台。在Nodejs端,每次接收到用户请求的时候都会判断用户的信息是否知足相关条件,而后从DB中读取相关静态文件信息渲染到index.html
中去。
简单总结下:将每次打包的静态文件信息先存储下来,以后请求到达Nodejs的时候判断用户是否知足相关条件,若是知足就读取DB将相关的静态文件信息返回给Nodejs,Nodejs将静态页渲染好以后返回给用户,达到灰度的目的。
使用Nodejs以前咱们的页面就是直接部署在服务其上,此次使用了Nodejs后,会有不少其它的问题须要作,好比说Nodejs服务的监控,多机房部署等。这些在大部分的公司应该都有相关的运维工程师来作。我这里简单介绍一些其它的内容
这里的规范包括本地开发时工程目录的规范和线上用户访问url的规范。
在笔者写这篇文章的时候最新的Nodejs版本已是 11.10
版本了,最新的LTS版本是10.15.1
版本。建议使用Nodejs的同窗都升级本身的Node到8.0
版本以上,由于8.0
版本是一个官方原生支持async...await
语句的版本。
.
├── client // 放置客户端的代码
├── index.html
├── index.js
├── node_modules
├── output
├── package-lock.json
├── package.json
├── server // 放置服务端Nodejs代码
├── test.sh
须要注意的就是在编写webpack打包工具的时候将server目录下的给排除掉。放置没必要要的编译和产出,增长打包速度。
当使用了新的服务的时候为了防止跟旧业务的冲突确定须要使用新的url。这个时候就须要作一些约定。目前咱们是这么约定的
// 域名/产品线/模块/ http://wwww.aaa.com/driver/bus/index.html // 域名/产品线/模块/静态文件目录 http://wwww.aaa.com/driver/bus/static/js/index.js http://wwww.aaa.com/driver/bus/static/css/index.html
前面提到此次业务升级咱们使用了新的url,可是为了保证业务的稳定性咱们不是一次性将全部的流量都切到新服务上去的。咱们也是经过批量的切的,因此会存在线上用户有的地区访问新服务有地区访问旧服务。那么有一天会有所有切换的一天,可是仍是会有一些用户访问到旧连接,这个时候能够经过配置Nginx 的`rewrite
来说旧连接都转成新的连接。
前端路由能够分为两种方式,hash和path切换。由于对于前端渲染页面来讲,当第一次请求完成后,其实全部的页面都已经下载到了本地(页面异步加载除外)。在咱们经过path切换页面的时候,每次都会向服务端发送请求,其实这些请求是不须要到达Nodejs服务的。咱们能够经过Nginx配置将这些无用的流量抵挡在Nginx这一层,减小服务器的压力。
若是是使用hash的方式则不存在这样的问题,可是会有另外的问题就是对搜索引擎不友好。固然前端路由切换仍是应该根据本身的业务作取舍。
当咱们应用了Nodejs服务以后,能够拓展的技术点有哪些,一下简单列举一些:
固然这种方案也不只仅是可使用Nodejs来作,也可使用其它语言。由于咱们公司已经有基于A/B测试的Nodejs-SDK。我这我就不具体介绍原理了。原理能够参考百度百科。若是有问题须要一块儿讨论能够留言或者是邮箱联系我:hpuhouzhiqiang@gmail.com