还记得十年前,当时就在追求页面在1s内打开,没想到十年后,我依旧在追求页面在1s内打开。
十年里,不管是客户端设备、客户端和服务端网络环境、服务端技术栈、甚至是开发语言技术栈都发生了不小的变化。
这次优化算是清理了几年前的技术债,简单记录一下吧。
第五次重构
如果你对之前的几次重构感兴趣,可以跳转文章尾部开始阅读。
九月的时候,我更新了配置并将运行了几个月的 Traefik
重启,进一步进行数据统计。
十一的时候,我购置了一台新的机器作为 Home Lab
,在将所有已有的服务进行了迁移,同时冗余的资源,可以提供给所有开发项目测试环境
和预发验证环境
。
在新环境的加持之下,原本完整编译发布的 1 分钟
可以被缩减到 40 秒
,如果配合缓存使用,时间可以缩减到 25 秒
之内。
在环境完备之后,我将九月运行至今(42天)的数据下载并进行统计,发现几个有趣的数据 (下面分别是包含、不包含爬虫的数据截图)。
- 个别请求响应时间慢
- 每天接近
200MB
的流量使用,其中有的资源要完整响应客户端,最大响应时间甚至到了30s
,个别例子甚至到了分钟级别,猜测是高频访问时刻,带宽被占满所致。
- 每天接近
- 静态资源效率不高
- 静态资源中,
common.css
、webfont
、core.js
、common.js
、sidebar-cover.jpg
请求数量巨大,占用了固定带宽,影响了一部分用户的访问体验,浪费了这部分用户的移动流量。
- 静态资源中,
- 古董浏览器用户不多了
- 访客操作系统中
Windows
、Mac
、Android
、iOS
等操作系统依次递减。访客浏览器占中IE
仅占4.56%
,IE
系列中IE 9
占了0.85%
,其他版本占比低到可以忽略。
- 访客操作系统中
- 404 资源需要进行兼容
- 包含爬虫在内,请求中有
14.18%
的请求出现了404,虽然流量只消耗了2.97%
,但是感觉应该进一步降低这个数值,毕竟要提供有价值和意义的内容呈现不是。
- 包含爬虫在内,请求中有
下面的截图是未重构前,包含异步加载图片的首页数据。
可以看到 384KB
的数据加载,让页面 DOM Ready
延迟到了 300ms
, 而页面完整加载硬是拖到了 994ms
。
寻遍访问记录,我发现轮播图内容的访问加起来不到 1%
,而且脚本中用于适配桌面、移动端设备的轮播代码包含组件库代码(脚本、样式),加起来接近 3k
,延时加载的几张图居然占用了总流量的 3%
,并且前面说到的完全加载时间被拖慢,这个组件功不可没,简直是猪队友,这种高投入低产出的组件,可以直接干掉。
为了照顾古董浏览器而使用的 jQ
库占用了接近 13%
的流量,结合上面的访客客户端数据,这个基础库该减肥了,在不大规模修改原来程序的基础上,考虑到最小成本替换,于是暂时使用 Zepto
进行了替换,源文件减少 60 KB
,GZip
后的文件尺寸 13KB
,而随后清理掉页面加载的一些 inline script
,每个页面的 GZip
后的尺寸又减少了 1KB
。
对于桌面系统展示的侧边栏的图片,占用了超过 10%
的流量,客户端分辨率越来越高,但是这个图片却不再好再进行尺寸上的扩张,一来浪费用户流量,二来还是投入产出比的问题,于是我使用几张 SVG
化后的图片对它们进行了替换,在 GZip
压缩之后,每张图片只占用不到 10 KB
,还能够应对未来分辨率的继续扩张的问题。
在查看页面数据的时候,我发现 common.css
和 Web Fonts
分别占用了总流量的 22.15%
和 13.47%
。前者源码居然 include
了大量未被使用的组件(前几版重构过程中操作失误)、后者居然没有使用定制的字体文件。在简单修正之后,两个文件总共减少了 100 KB
以上。至于暂时不使用 SVG SPRITE
,我是这样考虑的,虽然将图标和字体放在 SVG
中,甚至合并到页面内容中,能够进一步减少请求,但是势必要引入额外的脚本进行资源挂载,而且渲染性能影响过大,页面DOM复杂度也会提升,还不利于缓存复用。等未来 Web Components
支持进一步完善再说吧。
另外,在处理过程,顺便修正了 Node
和 Hugo TPL
存在的 ReDoS
的问题,现在网站中的多数文章应该都显示正常了。
最后贴一下这次重构的战斗结果(Lighthouse v3.0.3)。
还有请求数据(无缓存)。
暂时的缺陷:
PWA
完全没有做的情况下,得分58
。- 无障碍访问
88
分,失分在界面部分内容对比度不足,低分辨率的情况下不满足WCAG 2 AA
高对比度要到7:1
的要求。
回顾历史
虽然之前有说过,在去年已经对网站进行了全面升级,抛弃了传统的动态脚本,取而代之的是 Markdown
配合一个 DataBridge
进行全站静态生成,但是网站主题使用的还一直是在淘宝工作时使用的编写的模板。
第一版
2014年最初设计模板的时候,其中有几个小功能比较有意思。
- 资源加载全凭前端加载器,配合自动切换不同源头的资源,可以轻松做到站点资源永不失效。并且会针对不同的浏览器加载不同版本的jQ依赖库,从而在满足兼容性处理的情况下,提高执行性能。
- 模块粒度很细,但是入口统一由前端脚本把控,不论脚本、样式,还是资源,都由页面脚本引入,使用构建工具在编译时,再进行拆分优化。
- 尽可能避免
inline resource
,每类页面单独具备该页面的脚本和样式,减少编写时需要额外进行命名空间或者书写规避,同时减少爬虫以及用户刷新带来的额外传输损耗,提高资源缓存利用率,提高响应速度。 - 配合修改过的
nginx concat
,可以做到在不更新资源的情况下,动态对页面进行调试。
第二版
随后,随着 gulp
的衰落、webpack
的兴起,Markdown
的流行,BootStrap
的大版本升级,以及 SSL
证书的获取从难到易,CDN
流量从贵到便宜,Hexo
缺乏定制,网站服务器架构的变化… 网站又开始了变化。
- 使用
webpack
进行构建,基于AST
进行资源优化和拆分,替换掉之前使用AMD
进行资源显示声明以及手写工具的模式。 - 子域名合并,在
SSL
未开始普及的时代,从前普通HTTP
流量分发,像是七牛、新浪云可以作为低成本、甚至无成本的服务商,但是伴随HTTP 2.0
到来的SSL
,如果还继续使用多域名,带来的第一个问题便是你需要申请多个域名的证书(当时泛域名证书非常贵),以及支付不是很便宜的HTTPS
流量成本。 Hexo
之类的的静态站点生成器很多,但是当时几乎都需要将文章Meta
信息写在文章内部,并且对于特定目录结构的站点生成极其不友好,而且性能说实话不是很好。
第三版
2017年的时候,随着 Markdown
工具体验越来越好,考虑之后,实在没有必要在坚持使用 WordPress
作为内容管理,于是在博客架构中废弃了 WordPress
。并且当文章数量过千篇之后,Hexo
性能瓶颈越来越严重,交付于 CI
系统执行构建,需要消耗太多的资源,于是将其替换为 Hugo
。
- 在更换
Hexo
换为Hugo
前,我曾经挣扎着写过几个Hexo
的插件,但是性能真的太差了,如果要日常使用,必须准备一台起码2C2G
的云主机闲置,太浪费了。 - 但是使用
Hugo
之后,失去了对Node.js
这类容易“编辑执行”的程序能力后,想要达到之前的网站生成结果,除了修改Hugo TPL
外,所有的“花样”便只剩下在构建前后进行文件处理、或者使用客户端完善页面内容了,不过这样反而更加适合交付CI
,进行完全自动化。
第四版
今年五一假期的时候,网站在上一个版本的基础上运行了快一年的时间里,当初没有转换清理完毕的文章内容也陆陆续续的补齐了,在补齐内容的过程中,我进一步抽象了 DataBridge
,未来可以轻易切换到更多不同的静态站点生成工具或者静态发布平台上。
而随着一次次的迭代优化,CI/CD
流程和周边脚本也变的效率越来越高, 准备数据 -> 生成站点 -> 处理文件 -> 进行发布
,这一套流程从最初的 2 分钟缩减到了1 分钟。
最后
计划接下来再更新一轮,将未添加的 PWA
功能添加完毕,另外彻底移除不需要的 Lib
依赖,进一步提高网站呈现速度,然后再尝试能否将网站去中心化,借助不同服务提供商的 CDN 和 页面内埋入的版本控制脚本,变为“分布式”的网站,或许还会把网站关闭许久的评论功能补回来吧。
–EOF