目录
一、背景
在日常的前端开发中,倘若想验证一个业务功能正向性,需要针对部分用户进行灰度实验。
二、解决方案
方案 1:中转页
用一个轻量级的 H5 页面做流量中转,收集完用户信息后使用 Ajax
来请求后端接口来判断一个用户是否命中灰度,再通过 location.href
或 location.replace
来做相应的页面跳转。
优点:
- 适用于页面结构大不同的多个页面。
缺点:
- 两次页面加载页面,极其影响转化率。
- 不适用于只是模块小改的页面。
示例:
ajax.get('https://getwhich.com').then( abValue => { let jumpUrl = 'https://default.com' if (abValue === 'iAmExp') { jumpUrl = 'https://exp.com' } location.href = jumpUrl } )
方案 2:JavaScript 分流
在页面渲染的过程中,通过 Ajax
询问用户是否命中灰度,命中灰度则渲染灰度模块。
优点:
- 适用于快速迭代的小功能,开发量小。
缺点:
- 代码冗余,需要保留原有功能。
- 版本混乱,发版频繁的情况下,这段时间将伴随着其他功能的上线,若要排查问题或者回滚往往比较麻烦。
- 性能差,渲染前多一层网络请求后的判断。
- 维护成本增加,灰度结束后需要重新发版前端项目,以规避分流逻辑造成的损耗。
示例:
ajax.get('https://getwhich.com').then( abValue => { if (abValue === 'iAmExp') { render(ExpDOM) } else { render(DefaultDOM) } } )
方案 3:Nginx 分流
在服务器代理层就进行转发,需要在入口层、运维方和业务方三方配合。
优点:
- 网络层面更快,折损极小。
缺点:
- 公司运维方往往是比较独立的部门,参与业务开发合作时沟通成本和后期维护成本较高。
- 不适用于只是模块小改的页面。
方案 4:后端接口重定向(前端资源)
有点类似于 Nginx 分流,不过将运维部分的职责转移到了业务后端,将加载前端资源的链接替换成后端接口,在接口层做 302
重定向。
优点:
- 性能更好(相对于前端层中转),折损较小。
- 更加灵活,可用于分流 HTML、CSS、JavaScript 等资源。
- 维护成本低,回滚快,数据配置层即可控制分流。
示例:
loadScript('https://to-real-frontend-resource.com')
综上,方案 4 是比较合适的方案,不过后端将承担较重的职责。
三、技术方案
3.1 控制灰度量
MurmurHash 是一种非加密 Hash 算法,对于输入的值输出一个具备分布式的 32 / 64 / 128 位散列值。
/** * @method str2Murmur * @description 字符串转 Murmur Hash 分布式的百分比 1~100 **/ func str2Murmur (str string, seed int) int { murmur2 := MurmurHash2([]byte(str), uint32(seed)) denominator := math.Pow(2, 32) - 1 percent := float64(murmur2) / denominator percentInt := int(percent * 100) + 1 return percent, percentInt }
利用用户标识来生成 32 位的 HASH 值,再以 2^32 - 1
为分母来让其在 1 ~ 100
之间均匀分布来控制灰度的量。
3.2 约束流量准入条件
JsonLogic 是一个约束前端和后端过滤条件的规范,已经有 Golang JsonLogic 库做了开源。
{ "and": [ {"==": [{"var": "platform"}, "mm"]}, {">": [{"var": "v"}, 101]}, {"==": [{"var": "page"}, "home"]} ] }
以上 JSON 代表着同时满足平台(platform)是 mm、版本(v)大于 101、页面(page)是首页的过滤条件。