1. 前端发布策略
前端发布的本质,其实是静态资源的发布,一般是 js
、css
,而不包括动态渲染出来的html
模版。
野生状态下的前端资源
- 有一个HTML
- HTML中引入一个CSS
- CSS和HTML模版都有服务器反向代理
这时候他们的网络时序图会如下图所示,html
和css
会依此加载:
这种情况下我们可能会想到一些优化手段。
比如说能否用HTTP
的缓存提高资源的加载速度呢?
我们知道HTTP
的缓存有两种
- 协商缓存
使用协商缓存的话,浏览器去请求资源,服务器会告诉浏览器这个资源已经多久没有改变过了,浏览器发现这个时间内自己请求过这个资源,于是就把缓存的资源拿出来直接使用。
![image.png](https://yejiwei.com/static/img/455d457aecb19c383816b03f6ed65d46.image.png)
这种方式省去了重新下载整个资源的时间,但是仍然需要一次协商缓存的过程。
- 本地缓存
另一种是本地缓存,在这种方式下,浏览器在发起请求之前,会对比请求的
url
,如果发现和之前一致的话,就从硬盘或是内存中,找到对应的缓存,直接使用。
显然本地缓存对加载速度更好,但是本地缓存带来了新的问题,如果资源更新了怎么办?用户一直使用老的缓存,即使发布了新的版本,用户不是也用不上吗?
有人想到了一个办法,既然本地缓存更请求的url
有关,那么我们在请求资源的后面多加个版本的参数不就好了么,每次更新资源的时候也同步的更新参数。比如说:所有的资源都加上一个v.x.x.x
的版本号,在下次更新的时候修改版本号,让用户的缓存失效。
但是在实际情况中,我们还发现了新的问题,对于一个大型网站来说,静态资源可能非常非常多,每天都会有新的前端代码被修改,如果其中每一个资源被修改了,我们就全量修改所有的版本号的话。那缓存的意义也就不大了。
针对这个问题,我们可以用hash
来解决。
hash
是一串字符串,它像是文件的一种特质,只和文件的内容有关,如果一个文件的内容变了,那么它的hash值也会变化。
利用hash
的特性,我们可以把上一步的版本号改为hash
值,这样的话只有被我们改动过的静态资源的缓存才会失效。
看起来这是一种比较完美的解决方案。
不过,对于大公司来说,为了进一步提升网站性能,一般都会把静态资源和动态网页分集群部署,静态资源会被部署到CDN
节点上,网页中引用的资源也会变成对应的部署路径:
好了,当我要更新静态资源的时候,同时也会更新html
中的引用吧,就好像这样:
页面和静态资源不在同一个机器上,我们就要面临一个问题,他们两者的部署,就必然会有一个时间差,那么是先上线页面呢,还是先上线静态资源呢?
- 先部署页面,再部署资源:在二者部署的时间间隔内,如果有用户访问页面,就会在新的页面结构中加载旧的资源,并且把这个旧版本的资源当做新版本缓存起来,其结果就是:用户访问到了一个样式错乱的页面,除非手动刷新,否则在资源缓存过期之前,页面会一直执行错误。
- 先部署资源,再部署页面:在部署时间间隔之内,有旧版本资源本地缓存的用户访问网站,由于请求的页面是旧版本的,资源引用没有改变,浏览器将直接使用本地缓存,这种情况下页面展现正常;但没有本地缓存或者缓存过期的用户访问网站,就会出现旧版本页面加载新版本资源的情况,导致页面执行错误,但当页面完成部署,这部分用户再次访问页面又会恢复正常了。
好想都不太好...
最终方案:非覆盖式发布
之前的方案之所以有问题,是因为在CDN
上同名的文件只能有一份,它要么是老的要么是新的,不能同时存在,这种方式叫做覆盖式发布。非覆盖式发布就是指我们不通过url
参数带hash
的方法解决缓存问题,而是直接将hash
写入到静态资源的文件名中,这样的话不同版本的同一资源,文件名也不会重复,我们在发布时,将新的资源推送到CDN
之后并不会覆盖老的资源,它们两者在CDN
上同时存在,这个时候访问新页面的用户加载新的资源,访问老的页面的用户加载老的资源,各不冲突,这样就可以完美的解决资源更新的问题了。
2. 后端发布策略
后端发布的本质是后端服务再多台服务器上的分发。
对于大公司,往往不可能用单机承载所有的流量,而是有一个服务器集群,分摊高并发服务的成本,也挺高了服务的可用性。
后端发布关心的问题
- 如何减少用户感知上的新旧版本不一致
- 如何让发布过程中的服务尽可能的稳定
- 如何保证发布的结果最终一致性
下面介绍后端的集中部署方式
滚动部署
滚动更新的发布过程,是让应用的新版本逐步替换旧版本。在此期间,新旧版本会共存。
下图显示了该更新策略:旧版本显示为蓝色,新版本显示为绿色,它们部署在集群中的每一台服务器上。
三台服务器一开始都是老版本,然后在state 1
,state 2
阶段开始逐渐替换到新版本,最终完全替换成功,这个过程服务不会中断,一个请求可能会落在老版本中,也可能会落在新版本中。这种部署方式的特点:
- 节约资源(不需要额外服务器资源)
- 流量冲击小(应用逐步的被替换,过程是渐进式的,每台服务器承受的压力理论上是相同的)
- 回滚不及时
- 存在中间状态,可能会导致不一致
蓝绿部署
不停止老版本,部署新版本并进行测试,确认OK后,将流量切到新版本。
这种部署方式的特点:
- 风险小,新的版本有问题不会影响线上
- 便于快速回滚
- 切换流量要妥善处理未完成请求
- 整体切换流量冲击较大
灰度发布/金丝雀发布
灰度发布是滚动发布的改良,在原有软件生产版本可用的情况下,同时部署一个新的版本,两个版本同时存在于线上,为新版本分配少量流量,线上验证完毕后再将新版本推广。
这种部署方式的特点
- 渐进式,风险较小
- 需配合复杂的路由策略