大家好,我是「负雪明烛」,欢迎关注。
背景
两年前的 2020 年 3 月份,力扣(LeetCode 中国版)推出了「每日一题」活动。力扣网站上每天公布一道题目,吸引大家一起做题和讨论。
当时我因为疫情原因居家,足不出户。作为力扣爱好者,我正在想着自己组织「每日一题」打卡活动呢!
虽然第一反应是「哎呀,我想做的事情被力扣给做了!」。但是经过我老婆的点拨,我明白没有必要跟力扣竞争搞同样的「每日一题」的活动,应该发挥自己的特长,围绕着「力扣每日一题」活动搞社群。
于是当天晚上我就建立了一个「力扣每日一题打卡」小群,开始拉周围的好朋友进来凑数。在群里,大家可以一起讨论今天的力扣每日一题解法,并且互相监督打卡。
怎么检查群友打卡情况呢?
我调研了一下类似的打卡群,都需要在力扣上打卡完成之后发截图、再人肉统计。
群内人数很快到了 50 人,如果人肉统计每天的打卡情况,那多累啊!
**可我们是程序员啊!**遇到难题,咱们就开发个项目呗!
于是,我花了个周末,开发出来了「每日一题打卡网站」。地址是: ojeveryday.com
网站利用爬虫技术,统计所有成员是否完成了今天的题目。也就是说,成员只要在力扣上做完题目,这个打卡网站过会就把成员的状态更新为「已打卡」。
完全自动化,不需要额外操作!懒到极致!
网站上线两年了,现在是什么情况呢?
-
加入人数已经 3626 人;
-
建了 6 个打卡监督群;
-
产出一份开源算法刷题模板:AlgoWiki
-
包括本公众号最初也是为了打卡组织而创办的。
可是,最近发现打卡网站的打开速度实在是太慢太慢了,每次打开都需要漫长的等待。
通过 Chrome 的排查工具看一下,发现每次打开网页竟然需要 15 秒!
据研究,网民打开一个网站最长能忍受的打开时间是 6~8 秒;如果超过 12 秒,99%的用户都会直接关闭网页,不再等待。
网页打开的最佳时间是 2 秒!
所以,这网站到了不得不优化的时候了!拿起键盘干!
分析
网站加载慢的原因在哪呢?
通过对打开网站时的请求分析,我发现耗时比较长的操作在于「静态资源」和「后台接口」,都占据了 2 秒以上。
竟然还有一些静态资源请求失败了。。
所以思路就围绕着「优化静态资源加载速度」和「优化后台接口」两方面展开。
优化静态资源加载速度
首先看下静态资源怎么访问的。
耗时最久的 angular-1.2.10.js
是放在渣渣服务器上的,没有上CDN
。所以虽然访问成功,但是很慢。
而请求失败的jquery.dataTables.min.css
,虽然放在了CDN
上,但是是国外的 CDN
。访问失败应该可以理解吧!
所以,对于「静态资源」的优化,我采用的办法是把这些资源都放到国内CDN
。
随着云计算技术的普及,云服务器、CDN
这些服务其实都是触手可得,而且价格很便宜的。
我采用的某云的对象存储服务:
新建对象存储时,选择权限设置为「私有写,公有读」。
把网站中用到的静态资源使用厂商提供的上传工具上传到对象存储上。
再打开 CDN
加速。
当读取资源的时候,使用CDN
加速域名就可以了。
再打开网站看看静态资源加载速度如何:
以前这些耗时大户,现在访问时间基本在 60 ms 以内。
之前耗时最久的 angular-1.2.10.js
,访问时间从4.04s
,变成了 37ms
,加速了 100 倍!
之前访问失败的jquery.dataTables.min.css
和 jquery.dataTables.min.js
,现在不仅能正常访问,而且加载时间只需要 20ms
左右!
飞一般的感觉!
还能更快吗?
一个网站的静态资源,基本上很少有变化。浏览器会帮我们缓存静态资源。
当第一次打开网页的时候,所有资源都要从服务端获取。
但是当「刷新」或者关闭网页后间隔不长的时间「再次打开」时,静态资源是从磁盘/内存的缓存中读取的,因此速度极快是 0ms
。
至此「静态资源」优化完成。
接口加速
后台接口需要几秒钟才能返回结果,为什么这么慢呢?
看一下首页请求的这 4 个接口,分别是**「统计信息」、「打卡列表」、「更新时间」、「今日题目」**。其中「统计信息」、「打卡列表」两个接口耗时最长达到了 4 秒。
这两个接口都是带有参数的 date=2022-03-18
,即请求的今天的数据!
而后台接口只是把请求转成了 SQL
查询,所以怀疑是数据库的问题!
我的数据库采用的是某云厂商的云端 MySQL。
登录上去看一下,啊,果然没配索引!!
这个表的总行数多少呢?
竟然有 174 万行数据!!
也就是说,每次接口调用都需要从 174 万行数据中,筛选出日期是今天的所有打卡信息,再执行统计。
如果没有索引,那么就得遍历啊,时间复杂度是 O ( N ) O(N) O(N) !
在网站最开始上线的时候,数据比较少,因此接口访问速度挺快的。而现在数据已经有了上百万行,所以 SQL
执行的时间需要几秒钟。
既然知道问题在哪了,其实优化也就很简单了,加上索引就 OK 了,而且可以直接在界面上操作。
这里我对「日期」、「用户名」、「是否已打卡」这 3 列建立索引,索引方式是 BTREE
。
网站后台的接口代码是不需要任何修改的。
让我们再刷新下网页,看下现在的接口访问耗时:
之前耗时最长的「统计信息」接口 summary
的耗时从 4.04s
变成了 125ms
,速度提升了 32 倍!
另一个耗时很长的「打卡列表」接口 page
的耗时从 3.89s
变成了 101ms
,速度提升了 38 倍!
可见,索引对 SQL
执行速度的提升是非常大的!
最后
经过我上面的两处优化之后,现在打开网站的速度保持在 2s
以内!已经达到了「网页最佳打开时间」。
比如下面截图中显示1.6s
网页加载完成,而以前需要15s
,四舍五入,网站速度提高了 10 倍~~
总结一下,我主要做了两个优化:静态资源上传 CDN
、后端数据库加索引,分别提高了网页静态资源加载速度和后台接口影响速度。
CDN
、缓存、索引等都是计算机的基础概念,这次网站优化是对这些概念的简单理解与应用。
美团有句老话,叫做「苦练基本功」。
万丈高楼平地起,苦练基本功就是在打地基。
最后唠叨一句,由于我的小破站访问量不大,所以按量付费的 CDN
费用很低。如果你的网站流量比较大,还是要评估一下成本。
想加入力扣打卡监督群的朋友可以点击 http://www.ojeveryday.com/#/submit ,填写个人 LeetCode 的主页地址。我会拉你进群。
图片来源:
Unsplash, Digital Ocean