用了CDN就一定比不用更快嗎?

語言: CN / TW / HK

本文為掘金社群首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!

對於開發同學來說,CDN這個詞,既熟悉又陌生。

平時搞開發的時候很少需要碰這個,但卻總能聽到別人提起。

我們都聽說過它能加速,也大概知道個原因,但是往深了問。

用了CDN就一定比不用更快嗎?

就感覺有些懵了。但沒關係,今天我們換個角度重新認識下CDN。

CDN是什麼

對於數字和文字型別的資料,比方說名字和電話號碼相關的資訊。我們需要有個地方存起來。

我們通常會用mysql資料庫去存。

文字存在mysql中

當我們需要重新將這一資料取出的時候,就需要去讀mysql資料庫。

但因為mysql的資料是存在磁碟上的,單臺例項,讀效能到差不多5kqps就已經很不錯了。

看起來還湊合,但對於稍微大一點的系統,就稍微有點捉急了。

為了提升點效能,我們在mysql之前再加一層記憶體做快取層,比如常說的redis,讀資料優先到記憶體裡讀,讀不到才到mysql裡讀,大大減少了讀mysql的次數。有了這套組合拳,讀效能輕鬆上萬qps。

mysql和redis

好了,到這裡,我們說的都是我們平時比較容易接觸的開發場景。

但如果現在我要處理的,不再是上面提到的文字類資料,而是圖片資料

比如,我有一張帥氣的照片。就下面這張。

每次刷某音聽到有人翻唱蔡健雅的《letting go》的時候,我都忍不住想發這張圖。

並配文"還是忘不了"。


那麼問題來了。

這張圖片資料應該存在哪?,又該從哪裡讀?

我們回過頭去看mysql和redis的場景,無非就是儲存層加快取層

儲存層和快取層

對於圖片這樣的檔案物件儲存層不太可能再用mysql,應該改用專業的物件儲存,比如亞馬遜的S3(Amazon Simple Storage Service,注意後面是三個S開頭的單詞,所以叫s3),或者阿里雲的oss(Object Storage Service)。下面的內容,我們就用比較常見的oss去做解釋。

快取層,也不能繼續用redis了,需要改成使用CDNContent Delivery Network,內容分發網路)。

可以將CDN簡單理解為物件儲存對應的快取層。

CDN和OSS

現在就可以回答上面的提問,對使用者來說,這張圖片資料存在了物件儲存那,當有需要的時候,會從CDN那被讀出來。

CDN的工作原理

有了CDN和物件儲存之後,現在我們來看下他們之間是怎麼工作的。

我們平時看到的圖片,可以右鍵複製檢視它的URL。

1667103075060

會發現圖片的URL長這樣。

powershell https://cdn.xiaobaidebug.top/1667106197000.png

其中前面的cdn.xiaobaidebug.top就是CDN的域名,後面的1667106197000.png是圖片的路徑名。

當我們在瀏覽器輸入這個URL就會發起HTTP GET請求,然後經歷以下過程。

CDN的查詢流程

第一階段: 你的電腦會先通過DNS協議獲得cdn.xiaobaidebug.top這個域名對應的IP。

  • step1和step2:先檢視瀏覽器快取,再看作業系統裡的/etc/hosts快取,如果都沒有,就會去詢問最近的DNS伺服器(比如你房間裡的家用路由器)。最近的DNS伺服器上有沒有對應的快取,如果有則返回。
  • step3:如果最近的DNS伺服器上沒有對應的快取,就會去查詢根域,一級域,二級域,三級域伺服器。
  • step4:然後,最近的DNS伺服器會得到這個cdn.xiaobaidebug.top域名的別名(CNAME),比如cdn.xiaobaidebug.top.w.kunlunaq.com
  • kunlunaq.com是阿里CDN專用的DNS排程系統
  • step5到step7:此時最近的DNS伺服器會去請求這個kunlunaq.com,然後返回一個離你最近的IP地址返回給你。

第二階段: 對應上圖裡的step8。瀏覽器拿著這個IP去訪問cdn節點,然後,cdn節點返回資料。

上面第一階段流程裡,提到了很多新的名詞,比如CNAME,根域,一級域啥的,它們在之前寫的 「DNS中有哪些值得學習的優秀設計」有很詳細的描述,如果不瞭解的話可以去看下。


我們知道DNS的目的就是通過域名去獲得IP地址

但這只是它的眾多功能之一。

DNS訊息有很多種型別,其中A型別,就是用域名去查域名對應的IP地址。而CNAME型別,則是用域名去查這個域名的別名

對於普通域名,DNS解析後一般就能直接得到域名對應的IP 地址(又叫A型別記錄,A指Address)。

比如下面,我用dig命令發出DNS請求並列印過程資料。

powershell $ dig +trace xiaobaidebug.top ;; ANSWER SECTION: xiaobaidebug.top. 600 IN A 47.102.221.141

可以看到xiaobaidebug.top直接解析得到對應的IP地址47.102.221.141

但對於cdn域名,一波查詢下來,先得到的卻是一條CNAME的記錄xx.kunlunaq.com,然後dig這個xx.kunlunaq.com才能得到對應的IP地址

```powershell $ dig +trace cdn.xiaobaidebug.top cdn.xiaobaidebug.top. 600 IN CNAME cdn.xiaobaidebug.top.w.kunlunaq.com.

$ dig +trace cdn.xiaobaidebug.top.w.kunlunaq.com cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.243 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.241 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.244 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.249 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.248 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.242 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.250 cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.251 ```

看到這裡,問題就又來了。

為什麼要加個CNAME那麼麻煩?

CNAME裡指向的,其實是CDN專用的DNS域名伺服器,它對整個DNS體系來說,只是其中一臺小小的DNS域名伺服器,看起來就跟其他域名伺服器一樣,平平無奇。DNS請求也會正常打入這個伺服器裡。

但當請求真正打到它上面的時候,它的特別之處就體現出來了,當查詢請求打入域名伺服器時,普通的DNS域名伺服器返回域名對應的部分IP就夠了,但CDN專用的DNS域名伺服器卻會要求返回離呼叫方"最近的"伺服器IP。

CDN專用的DNS解析伺服器會返回就近的CDN節點IP


怎麼知道哪個伺服器IP裡呼叫方最近?

可以看到"最近"這個詞其實是加了雙引號的。

CDN專用的DNS域名伺服器其實是CDN提供商提供的,比如阿里雲當然知道自己的的CDN節點有哪些,以及這些CDN伺服器目前的負載情況和響應延時甚至權重啥的,並且也能知道呼叫方的IP地址是什麼,可以通過呼叫方的IP知道它所屬的運營商以及大概所在地,根據條件篩選出最合適的CDN伺服器,這就是所謂的"最近"。

舉個例子。假設地理位置最近的CDN機房流量較多,響應較慢,但地理位置遠一些的伺服器卻能更好的響應當前請求,那按理說可能會選擇地理位置遠一些的那臺CDN伺服器。

也就是說,選出來的伺服器不一定在地理位置最近,但一定是當前最合適的伺服器。


回源是什麼

上面的圖片URL,是https://cdn域名/圖片地址.png的形式。

也就是說這張圖片是訪問CDN拿到的。

那麼,直接訪問物件儲存能不能拿到圖片資料並展示?

比如像下面這樣。

powershell https://oss域名/圖片地址.png

這就像問,不走redis,直接從mysql中能不能讀取到文字資料並展示一樣。

當然能。

我之前放在部落格裡的圖片就是這麼幹的。

但這樣成本更高,這裡的成本,可以指效能成本,也可以指呼叫成本。看下下面這個圖。

1667101182393

可以看到直接請求oss的費用差不多是通過cdn請求oss的兩倍,考慮到家境貧寒,同時也為了讓部落格獲取圖片的速度更快,我就接入了CDN。

但看到這裡,問題又又來了。

上面的截圖裡,紅框裡有個詞叫"回源"。

回源是什麼?

當我們訪問https://cdn域名/圖片地址.png時,請求會打到cdn伺服器上面。

但cdn伺服器本質上就是一層快取,並不是資料來源,物件儲存才是資料來源

第一次訪問cdn獲取某張圖片時,大概率在cdn裡並沒有這張圖片的資料,因此需要到資料那去取出這份圖片資料。然後再放到cdn上。下次再次訪問cdn時,只要快取不過期,就能命中快取直接返回,這就不需要再回源。

於是訪問的過程就變成了下面這樣。

1668605964836

那還有哪些情況會發生回源呢?

除了上面提到的cdn上拿不到資料會回源站外,還有cdn上的快取過期失效了也會導致回源站。

另外,就算有快取,且快取不過期,也可以通過cdn提供的開放介面來觸發主動回源,但這個我們比較少機會能接觸到。


另外,回源這個事情,其實使用者是感知不到的,因為使用者去讀圖片的時候,只能知道自己讀到了還是讀不到。

同樣是讀到了,還細分為是從cdn那直接讀的,還是cdn回源讀物件儲存之後返回的

有快取直接返回和沒快取回源的區別

那麼,我們有辦法判斷是否發生過回源嗎?

有。我們接著往下看。


怎麼判斷是否發生回源

我們以某裡雲的物件儲存和CDN為例。

假設我要請求下面這張圖https://cdn.xiaobaidebug.top/image/image-20220404094549469.png

為了更方便的檢視響應資料的http header,我們可以用上postman

通過GET方法去請求圖片資料。

然後通過下面的tab切換檢視response header資訊。

檢視response header

回源的情況

此時檢視response header下的X-Cache的值是 MISS TCP_MISS。意思是未命中快取導致CDN回源查oss,拿到資料後再返回。

那此時CDN裡肯定是有這張圖片的快取了。我們可以試著再執行一次 GET 方法獲取圖片。

1667095186020

X-Cache的值就變成了 HIT TCP_MEM_HIT,這就是命中快取了。

這個是某裡雲的做法,其他比如騰某雲啥的,也都大差不差,幾乎都可以從response header裡找到相關的資訊。

用了CDN一定比不用的更快嗎?

看到這裡我們就可以回答文章開頭的問題了。

如果沒有接入CDN,直接訪問源站,流程是這樣的。

更新直接訪問源站

但如果接入了CDN,且CDN上沒有快取資料,那就會觸發回源。

更新走了CDN還回源

相當於在原來的流程上還多了一層CDN的呼叫流程。

也就是,用了CDN時,未命中CDN快取導致回源,就會比不用的時候更慢。

未命中快取,可能是cdn裡壓根就沒這一資料,也可能是曾經有這條資料但後來過期失效了

這兩種情況都正常,大部分時候並不需要做任何處理。

但對於極個別場景,我們可能需要做些優化。比如你們源站資料有大版本更新,就像更換cdn域名啥的,那在上線的那一刻使用者全用新cdn域名去請求圖片啥的,新CDN節點基本上百分百觸發回源,嚴重的時候甚至可能會拖垮物件儲存。這時候你可能需要提前將熱點資料篩選出來,利用工具預先請求一波,讓CDN載入上熱資料快取。比如某裡雲上的CDN就有這樣的"重新整理預熱"功能。

cdn重新整理預熱

當然也可以通過灰度釋出的模式,先讓少量使用者體驗新功能,讓這些使用者把cdn"熱"起來,然後再逐步放開流量。

還有就是曾經有這條資料但後來過期失效了,對於熱點資料,可以適當提高一下cdn資料的快取時間

1667344813600

什麼情況下不應該使用CDN?

從上面的描述看下來,CDN最大的優勢在於,對於來自世界各地的使用者,它可以就近分配CDN節點獲取資料,並且多次重複獲取同一個檔案資料的時候,有快取加速的作用。

這對於網頁圖片這樣的場景,是再合適不過了。因為底層用的是物件儲存,也就是說,只要是檔案物件,比如視訊啥的,都可以用這套流程接入cdn做加速。比如平時刷的某音某手短視訊就是這麼幹的。

那反過來想想,問題就來了。

什麼情況下不應該使用CDN?

如果你有一個公司內網的服務,並且服務請求的圖片等檔案不太可能被多次重複呼叫,這時候其實沒必要使用CDN。

注意上面兩個加粗了的關鍵點。

  • 內網服務,是為了保證你是瞭解服務的請求來源的,也能拿到物件儲存的讀許可權,並且如果你的物件儲存也是公司內部的,那大概率跟你的服務已經在同一個機房裡,這已經很近了。接入CDN也享受不到"就近分配CDN節點"所帶來的好處。
  • 圖片或其他檔案不太可能被多次重複使用,如果接入了CDN,那你每次去訪問CDN獲取圖片的時候,CDN節點上大概率沒有你要的資料,相當於每次都需要回源到物件儲存去取一把。那接入CDN相當於給自己加了一層代理,多一層代理,就多一層耗時。

1668612494972

關於上面的第二點,如果你需要一個明確的指標去說服自己,那我可以給你一個。從上面的介紹內容,我們知道,可以通過cdn響應的http header中的X-Cache欄位,看到一個請求是否觸發過回源,統計次數,再除以總的請求數,就能得到回源的比例,比如回源比例高達90%,那還接啥cdn。

總結

  • 對於文字類資料我們習慣用mysql做儲存,redis做快取。但屬於檔案類資料,比如視訊圖片,則需要使用oss等做物件儲存,cdn做快取。
  • 用了CDN如果發生回源,那實際上會比不用的時候更慢一些。
  • CDN最大的優勢在於,對於來自世界各地的使用者,它可以就近分配CDN節點獲取資料,並且多次重複獲取同一個檔案資料的時候,有快取加速的作用。如果你的服務和物件儲存都在內網,並且檔案資料也不太會有重複使用的可能性,那其實沒必要接入cdn。

最後

最近原創更文的閱讀量穩步下跌,思前想後,夜裡輾轉反側。

我有個不成熟的請求。


離開廣東好長時間了,好久沒人叫我靚仔了。

大家可以在評論區裡,叫我一靚仔嗎?

我這麼善良質樸的願望,能被滿足嗎?


別說了,一起在知識的海洋裡嗆水吧