HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

我们怎样将官网的加载时间缩短 1.7 秒?

  • 2020-05-16
  • 本文字数:2701 字

    阅读完需:约 9 分钟

我们怎样将官网的加载时间缩短1.7秒?


本文最初发布于 Casper 技术博客,经原作者授权由 InfoQ 中文站翻译并分享。


我们在 casper.com 上部署了一个变更,从我们自己的服务器而非供应商的服务器上加载一段第三方 JavaScript 代码。这个改动将初始渲染时间缩短了 1.7 秒:



在桌面 Chrome w/3G 网络下测试的数据


上文说的第三方 JavaScript 来自一家名为 Optimizely 的公司。通过使用他们的客户端 JavaScript,我们在 casper.com 上进行 a/b 测试。一旦 JavaScript 文件下载完成并执行,它将改变网站一半访客的文档,从而度量他们对变化的反应。为确保尽可能地避免文档样式短暂失效(FOUC),我们遵循的最佳实践是以阻塞方式最先加载 Optimizely。


正如我们所预期,采用这种方式加载 JavaScript 代码段会对我们网站的 Web 性能产生负面影响。


为此,我们在很长一段时间进行权衡。


我们是应该遵循 Web 性能最佳实践并异步加载 Optimizely JavaScript,还是遵循最佳实践的实验以阻塞方式加载?无论哪种,各有利弊。


我们想到的一个好方法是自托管 Optimizely 代码段。一般,像 Optimizely 这样的供应商会提供一个 JavaScript 文件的 URL(由他们托管)。问题是,这会导致新的 DNS 查询以及与供应商服务器之间新的 HTTP 连接和 SSL 握手。


用这种方式加载的另一项成本是,无法使用HTTP2多路复用来提供资产,而对于浏览器和服务器来说,这是一种更有效的通信方式。如下面的截图所示,从我们一项性能测试中可以看出,这会导致 DNS 查询延迟 39ms,建立服务器连接延迟 54ms,SSL 握手延迟 135ms。


此外,在等待第一个字节时有 175ms 的延迟,如果我们能使用 HTTP2 多路复用,就可以消除这一延迟。



自托管文件的最后一个好处是,我们能更好地控制边缘(CDN)和客户端(浏览器)缓存。Optimizely 不会让你控制它们的边缘缓存,但它们可以让你控制客户端缓存。有一个设置允许你配置 cache-control 值,我们将其设置为 2 分钟。对我们而言,当文件由 Optimizely 托管时,这是一个理想设置。


为了证明自托管更好,我们手动复制了 Optimizely JavaScript 文件的内容,并在服务器上保存了一个版本,同时,替换 staging 环境中的引用,指向我们的自托管版本。结果并不明显。这让人相当失望,以至于我们的数据分析师说,为了在初始渲染时间上节省 200 毫秒,不值得做这么多事。对这个说法,我们一致同意。



我们一直在坚持,因为我们认为 staging 环境不是很适合测试这种性能变化。我们的 staging 环境缺少很多只在生产环境中运行的第三方 JavaScript。所以我们设计了一个产品测试,在这个测试中,我们部署 Optimizely 的静态自托管版本,而数据分析师在 3 天内不对 Optimizely 做任何更改。



下降的时段是在 Optimizely 的自托管版本部署到生产环境期间(测量环境为桌面 Chrome、有线网络连接——当时我们没有在 3G 网络的速度下测量性能,这就是为什么文章一开始的图里效果更明显,但现在 3G 是我们测量时的标准网速)


从上图可以看到,当 Optimizely 代码段的自托管静态版本在生产环境中运行时,初始渲染时间出现下降。通过自托管,由于我们消除了 DNS 查询、Optimizely 服务器连接、SSL 握手、首字节时间,并启用了 H2 多路复用,所以初始渲染时间大大减少。


不过,我们还没有做好永久改变的准备。Optimizely 的工作方式是,如果对实验做了更改,JavaScript 代码段会在 Optimizely 服务器上更新。更改可能是开始/暂停一个实验,修改一个实验等等。你所做的任何更改都会生成新版本的 JavaScript 文件。


因为只是在生产环境中加载了手动复制的 JavaScript 文件的静态副本,所以我们不能一直保存它,因为那样我们就永远无法开始/暂停实验。对软件工程师来说,每次更改时都要手动复制新文件,这相当麻烦。


所以,既然我们看到这种方法的好处,就必须弄清楚如何从我们自己的服务器动态加载最新版本的 Optimizely 代码段。



为此,我们创建了一个每 60 秒运行一次的 AWS Lambda。当运行时,它会向 optimizely.com 发送一个 JavaScript 文件请求。它创建文件的散列,并检查 S3 以确定散列是否变化(我们将上次执行时的散列存储在 S3 上的一个文件里)。如果散列发生变化,则将新的 JavaScript 文件保存到 S3,文件名中包含散列的一部分(例如:snippet-c36d504bc3c26479f1181e6119617a64.js)。接下来,Lambda 将散列发送给我们 Fastly 边缘服务器上的一个字典。这就是奇妙之处。我们将边缘服务器配置为 ESI(Edge Side Include)和边缘字典的组合,动态地将最新的 Optimizely JavaScript 文件名插入到边缘服务器提供的每个页面的 HTML 中。这让我们可以在边缘处更新对 Optimizely 文件的引用,而不必每次文件更改时都重新部署网站。


以下是 WebPageTest 的截图,它测量的是由 Casper 托管的新 Optimizely 文件的性能:



下面是通过 WebPageTest 收集到的自托管前后的数据对比:



理想情况下,对于这些值,我们会提供实际用户监控(RUM)的 95 百分位数据,但对于 casper.com,我们还没有完全实现这一点。据推测,Optimizely 托管的时间(我们不确定是好是坏)和 Casper 托管内容的下载时间会有一些波动,因为这是合成测试。


这是一个 Chrome 瀑布流,显示了在 casper.com 和 Optimizely 文件上运用 HTTP2 多路复用的效果。请注意,前 5 个资产的内容下载几乎是在同一时间开始的。



最后,如前所述,自托管让我们能更好地控制缓存。我们将边缘服务器配置为将文件在边缘和浏览器缓存中保存整整一年。之所以能这样做,是因为文件名对于内容是惟一的(我们将文件散列的一部分添加到文件名中),并在内容更改时替换对文件名的引用。这样,如果我们不对 Optimizely 代码片段做任何修改,重复访客的浏览器甚至不会向 casper.com 请求文件。相反,它将直接从用户文件系统的缓存中提取文件。超级快!



如下图所示,你可以看到从浏览器缓存提供文件的好处:



这种方法的缺点是,当我们频繁地修改 Optimizely 的代码段时,网站访问者将无法体验到最优缓存。随着业务增长,我们的数据分析师可能会运行更多的 a/b 测试,这就需要频繁地修改文件。这可能导致网站访问者在访问 casper.com 期间需要下载多个版本的文件。我们在一个自定义的 DataDog 仪表盘跟踪 JavaScript 文件的每次修改:



在这个图表中,我们可以看到,在 23 日 3 个小时的时间里,代码段更改了大约 25 次。由于我们的平均访问持续时间不是很长,因此,不太可能有大量的访问者以这种更改频率下载代码段的多个版本。


总的来说,我们认为自托管的好处多于缺点。


我们的软件工程师、产品经理、站点可靠性工程师和数据分析师经过大约一个月断断续续的工作完成了这个项目。


英文原文:


How we shaved 1.7 seconds off casper.com by self-hosting Optimizely


2020-05-16 10:002202
用户头像

发布了 731 篇内容, 共 467.0 次阅读, 收获喜欢 1544 次。

关注

评论

发布
暂无评论
发现更多内容

基于Android的特征X射线谱识别系统的开发,android指纹识别

android 程序员 移动开发

大学计算机专业,什么水平可以进大厂?,解密Android开发常见误区

android 程序员 移动开发

天高任鸟飞,在你还苦闷Android出路时,总有人在系统钻研为高级开发做准备

android 程序员 移动开发

备战金九银十:Android面试10+个知识点总结宝典助你通关

android 程序员 移动开发

事务是如何影响你的系统(二)

卢卡多多

11月日更

大牛耗时一年:深入探索-Android-包体积优化,共三万字建议收藏上(1)

android 程序员 移动开发

大牛耗时一年:深入探索-Android-包体积优化,共三万字建议收藏上

android 程序员 移动开发

国内互联网公司为什么加班这么狠?(1),程序员翻身之路

android 程序员 移动开发

国庆节不知道学什么?这份 Android 优秀技术文章清单请收下

android 程序员 移动开发

在中国程序员是青春饭吗?,android开发基础入门教程

android 程序员 移动开发

坊间传言:程序员可以先在大厂镀金,以后去中小厂毫无压力

android 程序员 移动开发

大神一招搞定:ReentrantReadWriteLock-几道小小数学题就够了。

android 程序员 移动开发

回眸重探锁机制,高级android工程师

android 程序员 移动开发

“神算子”上线!EasyDL时序预测模型零门槛轻松上手

百度大脑

人工智能 百度

图解:HTTP 范围请求,助力断点续传(1),成功入职腾讯月薪45K

android 程序员 移动开发

在线等!阿里、百度一面就惨遭吊打,kotlin语言书籍

android 程序员 移动开发

基本功---Litho的使用及原理剖析,10年阿里开发架构师经验分享

android 程序员 移动开发

大学毕业做音视频开发,月入20K,你呢,kotlin协程面试

android 程序员 移动开发

大型Bat面试知识总结分享—AMS在Android起到什么作用?简单的分析下Android的源码

android 程序员 移动开发

因为不了解Android事件分发机制,居然被实习生嘲笑了,成长路线图

android 程序员 移动开发

在-View-上使用挂起函数,app开发面试题及答案

android 程序员 移动开发

备战秋招-阿里巴巴面试真题:-给你一个Demo-你如何快速定位ANR?

android 程序员 移动开发

大众点评App的短视频耗电量优化实战,通宵都要看完这个Android关键技术点

android 程序员 移动开发

Android线程思考

轻口味

android 多线程 11月日更

Google 的 Firebase 如何删除项目

HoneyMoose

国内互联网公司为什么加班这么狠?,音视频学习指南来咯

android 程序员 移动开发

图文DEMO并茂讲解RecyclerView滑动时回收和复用触发的时机

android 程序员 移动开发

图解:HTTP 范围请求,助力断点续传,android游戏开发入门

android 程序员 移动开发

在Android项目中接入Flutter,在Flutter使用安卓布局---草稿

android 程序员 移动开发

备战阿里面试一年半顺利通过二面,面对突如其来的疫情,让我的阿里三面搁浅ing

android 程序员 移动开发

大厂一步到位:Android-基础+Android高级,android物联网开发从入门到实战

android 程序员 移动开发

我们怎样将官网的加载时间缩短1.7秒?_文化 & 方法_Kyle Rush_InfoQ精选文章