2s : most users are willing to wait
10s : the limit for keeping the user’s attention focused on the dialogue
15s : tolerant time limit of most users
-- Fiona Fui-Hoon Nah, in A study on tolerable waiting time: how long are Web users willing to wait?, 2007css
网站访问速度是用户体验的重要组成部分。用户每每会给一个响应快速的网站较好的评价,而对于一个常常卡顿的网站则会留下团队技术水平较低的印象。(举例:美赛官网)所以,咱们在beta阶段对网站进行了各类优化,使用了缓存,CDN,优化加载等等手段,大幅提高了网站的访问速度。咱们打算首先就遇到的加载慢的问题进行分析,以后介绍一下咱们的解决方案与采起的技术,最后对比一下优化的效果。html
在咱们的网站被攻击后(详细),咱们决定采用CDN进行网站防御。在调研了各家公司的产品并检查了空空如也的预算后咱们决定采用CloudFlare的免费防御方案,并将网站部署在GitHub学生包搞来的vps上。在解决了恶意攻击问题后,咱们又遇到了新的问题:网站加载较慢。首页平均要5秒左右加载,而搜索页在条数比较多时甚至须要20秒左右加载完成。前端
咱们选取了三个典型页面利用chrome调试台作了分析,分别是首页(必定访问的页面),搜索全部课程页面(耗时最长,占用服务器资源最多),搜索“数学”关键字的页面(模拟随机搜索),加载的时间与瀑布图以下。python
首页:jquery
搜索所有课程:算法
模拟随机搜索:chrome
咱们逐个分析这三个页面加载缓慢的缘由,主要经过分析最花时间的部分。数据库
能够看到,首页元素中加载最慢的是背景图片与font。此外,网站页面加载与js加载也耗费了较长的时间。所以咱们打算采用静态资源使用公共CDN,网站使用cloudflare加速的方式解决。django
能够看到网页渲染耗费了最多的时间,此外,获取搜索结果也耗费了较长的时间(这里应该还有一个searchCourse的请求,不知道为何截取不到),搜索过程服务器占用较高。json
这个网页加载时间还算合格,可是其实是由于js资源在访问主页是被加载了,这里直接读了缓存。此外网站渲染时间依然较长。
对于搜索结果页面,咱们打算从前端代码(渲染逻辑)和后端(缓存),CDN(缓存)上解决。
为了解决上述页面的加载缓慢问题,咱们最后采用了如下技术:Django缓存,数据库建表缓存,网页渲染逻辑,CDN对于页面、资源的缓存,公共js/css库,图床。下面咱们来逐个介绍一下。
Django自带了一个较完善的缓存系统,用来对于一些频繁的请求或者占用资源的请求作一个缓存。咱们这里的搜索课程接口就比较符合缓存的需求,主要缘由有:搜索结果稳定,搜索过程在准备返回的json时会占用较多的资源(访问数据库,处理数据)。
Django缓存分为如下几种:Memcached、数据库、文件、本地内存以及GitHUb上的其余开源方法。具体部署能够自行谷歌或者参考这篇博客,部署过程比较简单。
在咱们的实际应用中,考虑到本机磁盘空间较充足,读写速度能够接受,又不想多配置其余软件,咱们使用了本地文件缓存的方式,并设置了缓存过时时间为15分钟。
关键代码以下:
settings.py:
CACHES = { # 基于文件的缓存,基于其余的缓存参考上面的博客简单修改这段便可 # 在测试时,应该使用 dummy cache 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': YOUR_CACHE_DIR_PATH, } }
在每一个须要缓存的view函数前面增长一个装饰器:
from django.views.decorators.cache import cache_page @cache_page(15*60) # 15 minute def xxx(request): yyy
咱们的获取评分排名接口是另外一个比较占用资源的接口。因为咱们的排名采起了一些科学的评分方法(详细),该算法执行一次时间随着评分条数增长而增长,有时须要2分钟左右,资源占用比上面的接口更加严重,并且若是是用户请求时再计算的话会致使网关超时,所以咱们采用数据库建表的方式进行缓存。
咱们经过一个定时任务(定时任务的使用方法能够参考教程),每两小时对课程,教师的排名进行一次更新,并将更新后的排名写入RankCache表。对于用户请求,直接在该表进行查表操做。这样就至关每两小时更新一次排名,用户查询的是最近一次更新的缓存。
关键代码以下:
settings.py增长:
CRONJOBS = [ ('* */2 * * *', 'ratemycourse.view.rankcache.cronjob','>> django_crontab.log') ]
以及在installed app里添加
'django_crontab',
rankcache.py:
这里具体的排名算法能够参考上面的博客的实现
def cronjob(): a=Rankers() # 声明排名类 a.read_data() # 从数据库里获取评分信息 a.run_rank() # 计算评分 a.save_to_database() # 将评分写入数据库rancache表
对于搜索结果页面,咱们在alpha阶段简单的一次性渲染了整个网页,加载了全部课程的div,致使了渲染时间较长。现阶段咱们改为了按需渲染,每次只渲染当前页面的几个课程信息,下降了渲染时间。
大体代码以下:
//2 得到到所要开始加载的课程序号 var course_to_show=(pagenum-1)*course_num_per_page; //3 加载页码内容,使用adddiv //将course_data清空 $("#course_data").html(""); for(var i = course_to_show;i < course_num && i < (course_to_show + course_num_per_page); i++){ //向course_data内插入 $("#course_data").append(adddiv(i)); }
咱们使用了cloudflare的免费套餐对网站进行了加速,基础配置流程十分简单,按照网站的步骤一步步作下来就好了。这里咱们介绍一下咱们针对咱们的网站作的特殊调整。
page rule是cloudflare提供的一个较高级的功能,相似IFTTT,根据规则对部分URL作针对性的缓存选择,支持正则匹配。page rule是cloudflare的一个较高级的功能,免费套餐支持3条,虽然不多可是足够使用。操做方法相似下图,输入正则的网站地址,选择add a setting,再选择具体操做便可。
咱们的配置以下:
具体描述是:针对得到全部评分接口,设置浏览器缓存过时时间2h,设置CF edge节点缓存过时时间2h,忽略querystring进行缓存。
实际上这个接口也能够作成Django缓存,可是咱们想尝试一下不一样的缓存方式,所以咱们采用了page rule。实际上采用page rule要略快一些,可能由于直接在edge节点就返回了缓存的信息,而不须要到达咱们的服务器。
因为咱们的网站曾经被攻击过,所以咱们打开了under attack mode。这个开关能够针对请求用户的IP等信息,提供6种不一样强度的js challenge,为网站提供防御。
cloudflare能够对html,js,css进行压缩,减少传输数据的大小。此外,还能够启用Brotli,http2,Mirage,Mobile Redirect等新协议,算法,框架进一步压缩网站数据,加快传输速度。这些设置能够在控制台的speed选项卡中修改。
咱们发现加载js,css,font也耗费了大量的时间。幸运的是,对于这些公共库,如jquery,bootstrap咱们彻底能够经过公共CDN进行加载,大幅提高这些文件的加载速度,节省服务器流量。通过调研,咱们发现今日头条,七牛云等都提供了这方面的服务,例如:今日头条CDN,Staticfile CDN。
一个例子以下:
// 修改前 <link rel="stylesheet" href="./css/bootstrap.min.css" type="text/css"> // 修改后 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.0.0-beta.2/css/bootstrap.min.css" type="text/css">
对于网站的全部公共css,js均可以在上述CDN的搜索页面中找到,复制对应连接替换便可。
对于背景图片等,咱们可使用公共图床进行加速。咱们使用了聚合图床,SM.MS 图床托管咱们的图片,加快访问速度。操做方法与上面js,css相似。
聚合图床能够一次性提供多个备份,并在请求时自动选择一个返回,通常返回的是上传到阿里cdn或七牛云的图片,使用前须要注册,高级功能,如api,最大图片张数等须要收费方案。
SM.MS图床主要特色是免费,不须要注册就可任意上传(100张/分钟),提供api,支持ipv6。主服务器应该在香港,所以相较于聚合图床ipv4访问会慢一点,部分开会日期可能会比较缓慢,可是校园网ipv6访问通常很稳定。
在使用了以上的方法后,咱们的网页加载速度有了大幅度的提高。咱们对比了alpha网页,alpha+CDN和beta(上述全部方法),效果以下:
首页 | 所有课程 | 随机搜索 | |
---|---|---|---|
alpha-CDN | 4.87s | 8.77s | 1.83s |
alpha-no CDN | 5.4s | 15.76s | 2.89s |
beta | 1.94s | 1.25s | 1.48s |
蓝色的是原始加载时间,橙色的是仅使用CDN的时间,灰色的是应用上述全部方法的加载时间。
可见,全部页面都有较大幅度的提高。
全部页面的瀑布图以下,顺序分别为alpha-no CDN,alpha-CDN,beta: