QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

我们怎样将官网的加载时间缩短 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:002252
用户头像

发布了 755 篇内容, 共 496.5 次阅读, 收获喜欢 1559 次。

关注

评论

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

云计算对比IDC的优势简单说明-行云管家

行云管家

云计算 服务器

闭关三月!啃透美团保姆级分布式进阶技术手册,终入美团定L8

Java 面试

我用Vanilla JS重写了一遍项目,结果……

Faye

大前端 js 原生

智慧海洋三维可视化,科技运维助工业物联网一臂之力

一只数据鲸鱼

数据可视化 3D可视化 智慧工业 海上作业

发布60分钟!霸榜Github的阿里面试参考指南,啃透涨薪10k

Java架构师迁哥

CryptoPlace挖矿APP系统开发简介

绍兴服装设计培训到兴德教育!

Geek_196d9f

绍兴柯桥CAD制图培训到兴德教育

Geek_196d9f

从零开始学习3D可视化之摄像机投影方式

ThingJS数字孪生引擎

大前端 可视化 3D 数字孪生

经过一年的不懈努力社招进了阿里,我总结了50个Java面试必考题

Java 程序员 架构 面试

所有前端都要看的2D游戏化互动入门基础知识

蚂蚁集团移动开发平台 mPaaS

大前端

趣口袋拼团系统APP开发案例

高并发应对策略系列文章阶段汇总,提供离线文档下载

Coder的技术之路

一文读懂大数据实时计算

五分钟学大数据

实时计算 7月日更

阿里新出炉爆款的顶配版Spring Security笔记,肝完变秃也变强

Java spring 编程 架构

喜马拉雅亿级用户量的离线消息推送系统架构设计实践

JackJiang

消息推送 即时通讯 IM push

架构实战营-模块八-作业

大可

Flink Runtime架构

Geek_qsftko

flink

点通生活系统软件开发搭建

hdfs 的集群间拷贝、归档、回收站等功能剖析

大数据技术指南

hdfs 7月日更

TY短视频系统APP开发介绍

新思科技凭借Coverity Scan帮助NGINX确保代码质量和安全

InfoQ_434670063458

新思科技 软件安全 Coverity 静态代码分析

搭建 JumpServer 堡垒机管理数万台游戏服务器

学神来啦

云计算 Linux linux运维 运维工程师 运维平台

面试官:你能讲讲栈和队列吗?我:你礼貌吗?

Ayue、

数据结构

万字图文丨最全的Java继承解读

华为云开发者联盟

Java 开发 代码 继承

【kafka实战】分区重分配可能出现的问题和排查问题思路(生产环境实战,干货!!!非常干!!!建议收藏)

石臻臻的杂货铺

Kafk Kafka实战

架构实战营模块8作业

eoeoeo

架构实战营

你见过最具有代表性的面试是什么样的?大三4面上岸腾讯(Java岗)

Java架构师迁哥

CodeDay 北京站报名倒计时

蚂蚁集团移动开发平台 mPaaS

移动开发

互帮侠系统软件开发公司

柯桥PS培训到兴德教育!零基础开始辅导!

Geek_196d9f

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