[技術博客]使用CDN加快網站訪問速度

[技術博客]使用CDN加快網站訪問速度

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

目錄

1. 發現問題

在咱們的網站被攻擊後(詳細),咱們決定採用CDN進行網站防禦。在調研了各家公司的產品並檢查了空空如也的預算後咱們決定採用CloudFlare的免費防禦方案,並將網站部署在GitHub學生包薅資本主義羊毛搞來的vps上。在解決了惡意攻擊問題後,咱們又遇到了新的問題:網站加載較慢。首頁平均要5秒左右加載,而搜索頁在條數比較多時甚至須要20秒左右加載完成。前端

2. 分析問題

2.1. 網頁加載時間與瀑布圖

咱們選取了三個典型頁面利用chrome調試臺作了分析,分別是首頁(必定訪問的頁面),搜索全部課程頁面(耗時最長,佔用服務器資源最多),搜索「數學」關鍵字的頁面(模擬隨機搜索),加載的時間與瀑布圖以下。python

首頁:jquery

alpha-withoutCDN-frontpage.png

搜索所有課程:算法

alpha-withoutCDN-all.png

模擬隨機搜索:chrome

alpha-withoutCDN-數學.png

2.2. 詳細分析

咱們逐個分析這三個頁面加載緩慢的緣由,主要經過分析最花時間的部分。數據庫

2.2.1. 首頁

能夠看到,首頁元素中加載最慢的是背景圖片與font。此外,網站頁面加載與js加載也耗費了較長的時間。所以咱們打算採用靜態資源使用公共CDN,網站使用cloudflare加速的方式解決。django

2.2.2. 搜索所有課程頁面

能夠看到網頁渲染耗費了最多的時間,此外,獲取搜索結果也耗費了較長的時間(這裏應該還有一個searchCourse的請求,不知道爲何截取不到),搜索過程服務器佔用較高。json

2.2.3. 模擬隨機搜索頁面

這個網頁加載時間還算合格,可是其實是由於js資源在訪問主頁是被加載了,這裏直接讀了緩存。此外網站渲染時間依然較長。

對於搜索結果頁面,咱們打算從前端代碼(渲染邏輯)和後端(緩存),CDN(緩存)上解決。

3. 採用的技術

爲了解決上述頁面的加載緩慢問題,咱們最後採用瞭如下技術:Django緩存,數據庫建表緩存,網頁渲染邏輯,CDN對於頁面、資源的緩存,公共js/css庫,圖牀。下面咱們來逐個介紹一下。

3.1. Django 緩存

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

3.2. 數據庫建表緩存

咱們的獲取評分排名接口是另外一個比較佔用資源的接口。因爲咱們的排名採起了一些科學的評分方法(詳細),該算法執行一次時間隨着評分條數增長而增長,有時須要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表

3.3. 網頁渲染邏輯

對於搜索結果頁面,咱們在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));
    }

3.4. CDN網站緩存

咱們使用了cloudflare的免費套餐對網站進行了加速,基礎配置流程十分簡單,按照網站的步驟一步步作下來就好了。這裏咱們介紹一下咱們針對咱們的網站作的特殊調整。

3.4.1. page rule

page rule是cloudflare提供的一個較高級的功能,相似IFTTT,根據規則對部分URL作針對性的緩存選擇,支持正則匹配。page rule是cloudflare的一個較高級的功能,免費套餐支持3條,雖然不多可是足夠使用。操做方法相似下圖,輸入正則的網站地址,選擇add a setting,再選擇具體操做便可。

咱們的配置以下:
page rule.png

具體描述是:針對得到全部評分接口,設置瀏覽器緩存過時時間2h,設置CF edge節點緩存過時時間2h,忽略querystring進行緩存。

實際上這個接口也能夠作成Django緩存,可是咱們想嘗試一下不一樣的緩存方式,所以咱們採用了page rule。實際上採用page rule要略快一些,可能由於直接在edge節點就返回了緩存的信息,而不須要到達咱們的服務器。

3.4.2. under attack mode

因爲咱們的網站曾經被攻擊過,所以咱們打開了under attack mode。這個開關能夠針對請求用戶的IP等信息,提供6種不一樣強度的js challenge,爲網站提供防禦。

3.4.3. 內容壓縮

cloudflare能夠對html,js,css進行壓縮,減少傳輸數據的大小。此外,還能夠啓用Brotli,http2,Mirage,Mobile Redirect等新協議,算法,框架進一步壓縮網站數據,加快傳輸速度。這些設置能夠在控制檯的speed選項卡中修改。

3.5. 公共js/css庫

咱們發現加載js,css,font也耗費了大量的時間。幸運的是,對於這些公共庫,如jquery,bootstrap咱們徹底能夠經過公共CDN進行加載,大幅提高這些文件的加載速度,節省服務器流量。通過調研,咱們發現今日頭條,七牛雲等都提供了這方面的服務,例如:今日頭條CDNStaticfile 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的搜索頁面中找到,複製對應連接替換便可。

3.6. 公共圖牀

對於背景圖片等,咱們可使用公共圖牀進行加速。咱們使用了聚合圖牀SM.MS 圖牀託管咱們的圖片,加快訪問速度。操做方法與上面js,css相似。

聚合圖牀能夠一次性提供多個備份,並在請求時自動選擇一個返回,通常返回的是上傳到阿里cdn或七牛雲的圖片,使用前須要註冊,高級功能,如api,最大圖片張數等須要收費方案。

SM.MS圖牀主要特色是免費,不須要註冊就可任意上傳(100張/分鐘),提供api,支持ipv6。主服務器應該在香港,所以相較於聚合圖牀ipv4訪問會慢一點,部分開會日期可能會比較緩慢,可是校園網ipv6訪問通常很穩定。

4. 加速效果

在使用了以上的方法後,咱們的網頁加載速度有了大幅度的提高。咱們對比了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的時間,灰色的是應用上述全部方法的加載時間。

time.png

可見,全部頁面都有較大幅度的提高。
全部頁面的瀑布圖以下,順序分別爲alpha-no CDN,alpha-CDN,beta:

alpha-withoutCDN-all.png

alpha-withCDN-all.png

beta-withCDN-all.png

alpha-withoutCDN-數學.png

alpha-withCDN-frontpage.png

beta-withCDN-frontpage.png

alpha-withoutCDN-frontpage.png

alpha-withCDN-數學.png

beta-withCDN-數學.png

相關文章
相關標籤/搜索