一篇搞懂金融行业的前端无损发布
写在前面
前后端开发、部署分离,前端发布是对业务开发团队来说是日常工作,如何做到发布对业务无损是每个前端人的追求。考虑到金融行业的服务特殊性,希望这篇文章可以帮助更多人了解金融业前端的无损发布流程。
一 前端发布的挑战
-
前端资源版本一致性
-
前后端代码版本一致性
-
白名单和百分比流量灰度
-
发布回滚
-
功能降级
以下逐步展开,介绍挑战的内容和解决办法。
前端发布的方案
- 前端资源版本一致性
关于前端资源版本一致性,这是个比较初级的问题,很多年前在知乎就有大佬讲解过,文章名字好像是“大厂如何进行前端发布”,感兴趣的可以去考古。但是我发现仍然有些团队未处理资源一致性问题,同时为了文章的完整性,这里做简要的说明。
通常在前后端分离的开发模式下,无论前端采用什么框架,比如 react、vue、ng等,前端的发布资源包一般类似如下结构:
yourModule/
index.html
js/index-e49cf0c9.js
其中,html的内容一般类似:
<!DOCTYPE html>
<html lang=zh-CN>
<head>
<meta charset=utf-8>
<meta http-equiv=Cache-Control content=no-cache>
...
</head>
<body>
<div id="root">
</body>
<script src="./js/app-h67cg0y7.js"></script>
<script src="./js/index-e49cf0c9.js"></script>
...
</html>
所谓的前端资源版本一致性,简单理解就是前端的 html 文件和对应的 js、css、image等文件版本一致。常见的不一致情况有:1、html 未进行“不缓存”设置;2、js 等文件未进行增量构建;
- 1、html 未进行“不缓存”设置
通常我们会要求运维把 html 的文件在 cdn 服务上配置不缓存,保证每次用户都从服务器上获取,虽然有流量损失,但是相比于用户可以在发布后第一时间获取最新的内容,会默认承受这部分流量损耗。但是有些团队可能会遗漏配置,导致发布后用户未正常更新html资源。
- 2、js 等文件未进行增量构建
上面的代码示例,你已经注意到 js 的文件名称是带一串字符的,如 app-h67cg0y7.js index-e49cf0c9.js ,原理就是对构建后的文件内容做 md5 摘要,若内容发生变化则文件名会带上新的摘要,常用前端框架均已实现这个功能,实现了增量更新。
通常 js 等文件资源的缓存时间都比较长,如果不采用这种方式,比如每个版本都是 app.js index.js,那么用户访问的 js 资源可能会出现旧的 app.js 和 新的 index.js文件,那么用户大概率会出现白屏问题。
二 前后端代码版本一致性
由于前后端分离部署,那么前后端发布时间一定有间隔。那么在间隔期间,仍然有流量进来的,务必要保证这段时间访问的请求是正常的。
在开发设计阶段,对后端的要求是接口做到向上兼容,同时在发布流程严格要求先后端再前端的发布顺序,才能保证发布间隔服务无感。
举个例子,后端应用v1版本的 api 入参是 name: string,v2版本的入参是 name: string; channel: string,那么 v2 需要兼容 v1 的入参类型。
当然上面的例子比较简单,其他复杂的场景也有处理方案,但是需要在开发设计阶段养成向上兼容的习惯,在团队内形成共识。
三 白名单和百分比流量灰度
虽然待发布的代码已经被测试通过,但是生产环境的数据状态复杂,仍然会出现未覆盖的场景。如果隐藏的bug被直接发布到生产,全量对外,那么影响面会被放大。为了减少潜在的问题影响,通常我们会先发布到灰度环境进行验证。
灰度环境的实现原理方式比较多,比如可以把资源发布到生产域名下的其他非投放路径,开发通过扫码访问来验证;也可以把生产包发布到测试域名,通过手动hack跨域限制完成验证;这两类方式通常被认为是非安全的灰度验收方式,并且不能同时验证到后端的灰度环境,不建议使用。
正规的灰度实现方式,是通过在客户端app打标,实现资源请求和接口请求的灰度。灰度的核心原理在于灰度标识的请求会被 nginx 分流。
在 App 中,webview 负责资源请求, native http 桥负责api接口请求,那么在请求发起时,带上灰度标识,比如在header中增加 x-gray:1,那么 nginx 会返回灰度资源或者数据。
实际工作中,大厂一般都有灰度配置服务,比如配置白名单、配置分流策略、下发灰度标识,给 CDN 厂商提需求,去识别灰度标识并返回灰度资源,api 请求会被nginx 根据灰度标识分流到灰度集群。后端仍然会有其他关联方,那么会有基础服务把灰度标识透传到其他后端服务,比如应用或者消息,具体不再展开。
流量百分比的灰度方式,核心在于百分比分片打标,一般通过设备号取模分桶,然后命中圈选逻辑的设备会被打上灰度标识,保证后续的请求不会在灰度和生产之间漂移。
四 发布回滚
发布后,一旦生产出现问题,影响用户使用,那么第一时间不是排查问题,而是回滚。因为银行金融业的生产问题,超过一定时间或者超过一定客户数量是需要上报人行监管机构,所以出了问题要通过回滚快速解决。有别于后端应用回滚实时生效的特点,前端的资源最终是部署在CDN运营商的节点上,从回滚开始到cdn刷新完成,通常需要10分钟左右。当然回滚有一定概率出现失败的情况,这时候一般通过重新发布上个版本的资源包来解决顽固CDN节点缓存不生效的问题。
五 功能降级
发布后,如果出现的问题是在开发设计过程中考虑到的,那么可以通过主动降级来实现。
举个例子,前端页面某个楼层是新增的,那么这个组件是否显示是可以通过后端api返回的情况来控制的。如果当这个区域出现生产bug,那么执行后端配置变更即可实现功能隐藏降级。
通常来说,后端的功能开关是通过配置化文件存储在redis来实现的,有的团队把后端的配置服务通过api单独暴露给前端使用,但是这样的设计会导致对于某个功能开关逻辑分散,开关需要协同,后续清理开关代码成本高,并且前端会多调用一个api影响性能。
最好的处理方式是,后端api把开关逻辑实现,在对前端的api 协议字段上体现,前端仅面向接口协议编程即可实现功能降级的能力。
以上。