朱雀-新一代前端分发解决方案[一]

想要毫秒级切换网站版本吗?想要快速实现灰度吗?快来看最新的源代码把。 项目地址:GITHUB

精益求精

灵魂提问:前端的发版应该式怎么样的?

这里简单说一下我们之前的发版流程。首先,前端的源代码式放在gitlab上的。这样开始发版的时候,只需要Jenkins配置好,就能一键启动。

具体流程:

  1. Jenkins从gitlab上拉代码到本地。
  2. 执行运维内嵌的脚本(通常使用pipeline),启动项目的依赖安装。
  3. 执行运维内嵌的脚本,启动项目的编译,生成静态文件。
  4. 启动docker build,基座使用nginx。将相关资源打包成镜像。
  5. 推送到k8s系统中,执行相关pod的启动和销毁。

上面这个就是简单的Jenkins流程,换成其他的打包系统,整体流程是不变的。那么问题来了,这里的设计已经很先进了,还有什么要改进的?

我的问题

工作中确实可以简单的实现前端发布,甚至是推给后端,让他们做一个简易版。一个ftp就可以搞定。但是这些是完全不够的。做技术还是要有那么一些追求的。比如,怎么样做的更牛比,怎么样设计的更高效。

经过我的思考,问题如下:

  1. 依赖安装过于占用时间,需要优化。
  2. 编译之后的静态资源要放到CDN上。(这一步很简单,大部分人都可以轻松办到)
  3. 基于nginx的前端存在缓存问题,每次发版都有可能出现用户资源未更新的情况。假如你说增加no-cache参数,那么问题就变成了用户每次都要拉资源,太慢了,不合理。
  4. 如果项目要随时上线,那么切换测试环境和生产环境有重新编译的可能(大部分网站在业务增加之后都有测试环境和生产环境2套配置)。QA对这个流程不放心,而实际上也确实可能存在换环境就出问题的可能。
  5. 如果项目要进行小范围测试(或者是线上验证)。那么只能发布到线上再进行验证。如果有流量进来,又恰好代码出了问题,那么就会造成实际的线上bug。
  6. 最后就是通知了。编译或者上线要有通知,这样才能让相关人员看到进度。

这些问题都不算严重问题,是可以随时克服的(QA和运维克服)。但是本着极客精神,我们要探索所有的可能性。

方案确定

编译前优化

编译前的很多动作是可选的,这里列举一些措施,后面的具体实现中就不做详细说明了。

  1. 打包工具的优化。常用的webpack已经过时了,单线程低效率的打包已经不能满足日益复杂的项目。需要替换成多线程高效率的打包工具。比如rspack、esbuild、swc等等。
  2. 代码检查的优化。可以在某个节点增加代码检查的流程。比如在提交前检查代码格式(很多现成的,比较好集成)。或者是合并到主分支前的代码扫描,gitlab增加hooks或者流水线,合并前执行sonar的代码扫描。还可以增加一个通知,把扫描结果发到群里。
  3. 增加私有库。私有库可以放一些公司内部的库,同时也能一定程度提高依赖安装速度。(私有库的网络设计不好,会导致公有库的包更新不及时甚至更新失败)

编译中的优化

这个阶段已经把代码拉到了编译服务器的磁盘中,我们要优化的是编译的时长。根据不同的阶段,可以简单分成需要依赖的编译流程和不需要依赖的编译流程。

需要安装依赖

这个阶段大致分成两种可能,可以单独去处理。

  1. 新项目,本地没有任何历史记录。不需要考虑任何优化,所有事情都要做一遍。
  2. 老项目,package.json有版本更新。这里需要注意的是有的人可能会把一个依赖复制两次,需要兼容这种情况。

优化手段比较简单,主要是检查到上面两种情况之一就执行npm install来安装依赖。也可以执行npm ci来减少信息输出,可以加快一点安装速度。同时,还要考虑,当本地缓存有问题的时候,要删除缓存再执行命令。

不需要安装依赖

正常项目其实只是业务逻辑的更新,了不起增加几个新页面。在这种情况中,我们是不需要安装依赖的,在编译流程中完成可以去掉这个流程。可以极大的减少发布时间。在发布脚本中需要判断当前项目是哪种情况,从而动态执行依赖安装流程。

其他优化

由于案例项目是使用Jenkins来发布的,所以还需要增加Jenkins的优化。在发布选项中增加额外的参数来。

  1. 增加选项,控制是否清空本地缓存。
  2. 增加选项,是否手动执行安装依赖。

编译后的优化

这个案例中编译后会执行镜像打包的流程。有些公司使用的是虚拟机或者云服务器,我们从简单的开始讲。

使用云服务器

这个模式下,基本就是搭建一个nginx服务,将文件推到ngxin的目录中。好处是简单实用,坏处是不够友好。

  1. 解决静态资源更新不及时问题。静态资源直接同步(比如ftp或者sync之类的方式)到nginx引用的目录,如果遇到用户正在下载,就会出现部分静态资源404的清空。解决办法:
    1. 静态资源先同步到一个固定文件夹,再完成之后一次性复制到nginx下。适用于用户较少访问的情况。
    2. 实用CDN。先把静态资源同步到CDN服务,再确定同步成功之后,直接同步到云服务器即可。
  2. 解决同步失败和回滚问题。由于网络或者其他情况,会导致同步文件失败。有时候也会遇到要回滚的情况。
    1. 可以按照固定格式创建同步文件夹,静态资源先同步到这里,然后再复制到nginx下。
    2. 或者也可以在同步完成之后,直接修改nginx配置,重启nginx就行。

使用容器方式

打包成镜像再推送到服务器可以简化流程,减少可能出现的问题。但是镜像有它自己的需要优化的点。

  1. 优化镜像大小。可以尽量挑小基座来打包。比如:nginx-alpine,只有17MB。或者是alpine-slim,只有5MB。这些小镜象缺少一些常用的库,如果是对这个有依赖,可以尝试手动安装,或者是更大一些的基座。还有就是优化dockerfile中的流程,减少layout,尝试使用缓存。
  2. 优化镜像大小2。这里的大小指的是镜像中静态资源的大小。使用CDN之后很多js、css文件已经不再需要打包到镜像中了。这里可以将这些内容去除,留下必要的内容。
  3. 优化启动顺序。pod启动是相当快的,但是假如你的pod中有一些后启动或者慢启动的项目,就要考虑太快启动造成的问题。这里可以在k8s中增加探活的机制。只有新的pod可用之后再切换新老pod的使用。其次就是旧的pod必须要等流量完全没有之后再销毁。

上线后的优化--重构

其实我们现有的项目已经很不错了。可以做到很便捷的上下线,同时也尽量减少了人工出错的可能。但是这些还不够,还要增加上面提到的几个优化。

新的优化不再依赖nginx的静态资源分发,需要我们自己处理:

  1. 编译之后的静态资源存CDN(降级处理可以存本地,作为一个冗余备份)。
  2. 入口文件index.html存数据库,可以设定测试换自动生效,生产环境自动进入灰度。
  3. 增加校验,防止本地开发发布到测试环境或者生产环境。
  4. 增加域名管理,根据不同的域名处理不同的项目。多项目,每个项目使用不同的域名情况下,需要隔离开每个域名的绑定内容。
  5. 增加配置管理,每个环境有自己独立的配置,可以增加基础配置,用来检验不同环境的配置是否必填等。
  6. 增加灰度能力。看情况开发,比如线上试用,走百分比灰度。线上验收,走体验版本或者白名单。小范围内部验证,走ip定向灰度。
  7. 快速切换能力。上线和回滚只需要点一个按钮就行。
  8. 缓存。不同的版本切换要清空缓存,同一个版本多次访问,要利用缓存。

以上内容已经足够独立成一个项目了。在一个正经的项目中,我们还要增加额外的支持能力:

  1. 用户管理、权限管理。不同的用户要区分开,不能每个人都去上线发布。
  2. 快捷登录。每个公司都会有自己的用户体系,可以集成这些鉴权。比如ladp或者钉钉等。我们接入的是钉钉,可以将页面嵌入在钉钉的应用栏中,快捷登录使用。
  3. 记录日志。每一个操作都应该留痕,要清晰的知道是谁操作了,同时记录操作改了哪些内容。

未来规划

我们在项目中已经稳定运行了一年多的时间。经过了多次发版的验证,可以很明确的感受到发版的效率在提高。不管是白天还是晚上,可以随时发版。在不影响线上的情况下可以做到线上回归验证。前端再也不用等待发版了,我们可以一边刷手机,一边等其他人操作。要是遇到问题,我们也能急速回滚,从开始回滚到旧版本生效,甚至不会超过1秒。

当然,我们也准备了接下来的规划。将现有的能力拓展的更加厉害。

  1. 更好的配置管理。配置已经可以做到注入页面使用了,但是还缺乏校验、已经语法提示。接下来在不增加操作难度的情况下,增加配置内容的校验,已经在开发中动态注入字段和提示。
  2. 自由创建测试环境。现有的环境还是固定的几个(其实已经可以自由切换了),但是我们要在现有的基础上增加无限多的测试环境。谁都可以给自己创建一套环境,联调和测试再也不怕环境不够用了。
  3. 更多的快捷登录和权限。现有的权限比较简单,控制的还不够精细,我们计划在未来增加更精细的权限控制。
  4. 手动修改HTML内容。在实践中,其实还有一个小小的需求,就是可能需要手动改一些html的内容,未来也将增加这部分的规划。

项目现在已经开源,愿意动手的已经可以下载下来试用了。如果还不太了解,也可以在demo中研究一下各种功能。目前的demo还不支持自由创建域名,只有一个域名也可以简单看看使用效果。

项目地址:GITHUB

DEMO地址DEMO

测试的域名:测试域名

更多代码和流程的解析请看后续文章。

相关推荐
程序员海军8 分钟前
2024 Nuxt3 年度生态总结
前端·nuxt.js
m0_7482567818 分钟前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web135085886351 小时前
前端node.js
前端·node.js·vim
m0_512744641 小时前
极客大挑战2024-web-wp(详细)
android·前端
若川1 小时前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点1 小时前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256564 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@4 小时前
HTML5适配手机
前端·html·html5