前端遇上Go: 静态资源增量更新的新实践

作者:网友投稿 时间:2018-07-12 09:17

字号
开发者盛宴来袭!7月28日51CTO首届开发者大赛决赛带来技术创新分享

 为什么要做增量更新

美团金融的业务在过去的一段时间里发展非常快速。在业务增长的同时,我们也注意到,很多用户的支付环境,其实是在弱网环境中的。

大家知道,前端能够服务用户的前提是 JavaScript 和 CSS 等静态资源能够正确加载。如果网络环境恶劣,那么我们的静态资源尺寸越大,用户下载失败的概率就越高。

根据我们的数据统计,我们的业务中有2%的用户流失与资源加载有关。因此每次更新的代价越小、加载成功率越高,用户流失率也就会越低,从而就能够变相提高订单的转化率。

作为一个发版频繁的业务,要降低发版的影响,可以做两方面优化:

更高效地使用缓存,减少静态资源的重复下载。

使用增量更新,降低单次发版时下发的内容尺寸。

针对第一点,我们有自己的模块加载器来做,这里先按下不表,我们来重点聊聊增量更新的问题。

增量更新是怎么一个过程

看图说话。

前端遇上Go: 静态资源增量更新的新实践

增量更新的客户端流程图

我们的增量更新通过在浏览器端部署一个 SDK 来发起,这个 SDK 我们称之为 Thunder.js 。

Thunder.js 在页面加载时,会从页面中读取最新静态资源的版本号。同时, Thunder.js 也会从浏览器的缓存(通常是 localStorage)中读取我们已经缓存的版本号。这两个版本号进行匹配,如果发现一致,那么我们可以直接使用缓存当中的版本;反之,我们会向增量更新服务发起一个增量补丁的请求。

增量服务收到请求后,会调取新旧两个版本的文件进行对比,将差异作为补丁返回。Thunder.js 拿到请求后,即可将补丁打在老文件上,这样就得到了新文件。

总之一句话:老文件 + 补丁 = 新文件。

增量补丁的生成,主要依赖于 Myers 的 diff 算法。生成增量补丁的过程,就是寻找两个字符串最短编辑路径的过程。算法本身比较复杂,大家可以在网上找一些比较详细的算法描述,比如这篇 《The Myers diff algorithm》,这里就不详细介绍了。

补丁本身是一个微型的 DSL(Domain Specific Language)。这个 DSL 一共有三种微指令,分别对应保留、插入、删除三种字符串操作,每种指令都有自己的操作数。

例如,我们要生成从字符串“abcdefg”到“acdz”的增量补丁,那么一个补丁的全文就类似如下:

=1\t-1\t=2\t-3\t+z

这个补丁当中,制表符\t是指令的分隔符,=表示保留,-表示删除,+表示插入。整个补丁解析出来就是:

保留1个字符

删除1个字符

保留2个字符

删除3个字符

插入1个字符:z

具体的 JavaScript 代码就不在这里粘贴了,流程比较简单,相信大家都可以自己写出来,只需要注意转义和字符串下标的维护即可。

增量更新其实不是前端的新鲜技术,在客户端领域,增量更新早已经应用多年。看过我们《美团金融扫码付静态资源加载优化实践》的朋友,应该知道我们其实之前已有实践,在当时仅仅靠增量更新,日均节省流量达30多GB。而现在这个数字已经随着业务量变得更高了。

那么我们是不是就已经做到万事无忧了呢?

我们之前的增量更新实践遇到了什么问题

我们最主要的问题是增量计算的速度不够快。

之前的优化实践中,我们绝大部分的优化其实都是为了优化增量计算的速度。文本增量计算的速度确实慢,慢到什么程度呢?以前端比较常见的JS资源尺寸——200KB——来进行增量计算,进行一次增量计算的时间依据文本不同的数量,从数十毫秒到十几秒甚至几十秒都有可能。

对于小流量业务来说,计算一次增量补丁然后缓存起来,即使第一次计算耗时一些也不会有太大影响。但用户侧的业务流量都较大,每月的增量计算次数超过 10 万次,并发计算峰值超过 100 QPS 。

那么不够快的影响是什么呢?

前端遇上Go: 静态资源增量更新的新实践

我们之前的设计大致思想是用一个服务来承接流量,再用另一个服务来进行增量计算。这两个服务均由 Node.js 来实现。对于前者, Node.js 的事件循环模型本就适合进行 I/O 密集型业务;然而对于后者,则实际为 Node.js 的软肋。 Node.js 的事件循环模型,要求 Node.js 的使用必须时刻保证 Node.js 的循环能够运转,如果出现非常耗时的函数,那么事件循环就会陷入进去,无法及时处理其他的任务。常见的手法是在机器上多开几个 Node.js 进程。然而一台普通的服务器也就8个逻辑CPU而已,对于增量计算来说,当我们遇到大计算量的任务时,8个并发可能就会让 Node.js 服务很难继续响应了。如果进一步增加进程数量,则会带来额外的进程切换成本,这并不是我们的最优选择。

更高性能的可能方案

“让 JavaScript 跑的更快”这个问题,很多前辈已经有所研究。在我们思考这个问题时,考虑过三种方案。

Node.js Addon

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
关键词 >>Go 前端 更新
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接