[技術博客]使用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?, 2007

網站訪問速度是用戶體驗的重要組成部分。用戶往往會給一個響應快速的網站較好的評價,而對於一個經常卡頓的網站則會留下團隊技術水平較低的印象。(舉例:美賽官網)因此,我們在beta階段對網站進行了各種優化,使用了緩存,CDN,優化加載等等手段,大幅提升了網站的訪問速度。我們打算首先就遇到的加載慢的問題進行分析,之后介紹一下我們的解決方案與采取的技術,最后對比一下優化的效果。

目錄

1. 發現問題

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

2. 分析問題

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

我們選取了三個典型頁面利用chrome調試台做了分析,分別是首頁(一定訪問的頁面),搜索所有課程頁面(耗時最長,占用服務器資源最多),搜索“數學”關鍵字的頁面(模擬隨機搜索),加載的時間與瀑布圖如下。

首頁:

alpha-withoutCDN-frontpage.png

搜索全部課程:

alpha-withoutCDN-all.png

模擬隨機搜索:

alpha-withoutCDN-數學.png

2.2. 詳細分析

我們逐個分析這三個頁面加載緩慢的原因,主要通過分析最花時間的部分。

2.2.1. 首頁

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

2.2.2. 搜索全部課程頁面

可以看到網頁渲染耗費了最多的時間,此外,獲取搜索結果也耗費了較長的時間(這里應該還有一個searchCourse的請求,不知道為什么截取不到),搜索過程服務器占用較高。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM