對于開發(fā)同學(xué)來說,CDN 這個詞,既熟悉又陌生。
平時搞開發(fā)的時候很少需要碰這個,但卻總能聽到別人提起。
我們都聽說過它能加速,也大概知道個原因,但是往深了問。
用了 CDN 就一定比不用更快嗎?
就感覺有些懵了。但沒關(guān)系,今天我們換個角度重新認(rèn)識下 CDN。
CDN 是什么
對于數(shù)字和文本類型的數(shù)據(jù),比方說名字和電話號碼相關(guān)的信息。我們需要有個地方存起來。
我們通常會用 mysql 數(shù)據(jù)庫去存。
當(dāng)我們需要重新將這一數(shù)據(jù)取出的時候,就需要去讀 mysql 數(shù)據(jù)庫。
但因為 mysql 的數(shù)據(jù)是存在磁盤上的,單臺實例,讀性能到差不多 5kqps 就已經(jīng)很不錯了。
看起來還湊合,但對于稍微大一點的系統(tǒng),就稍微有點捉急了。
為了提升點性能,我們在 mysql 之前再加一層內(nèi)存做緩存層,比如常說的 redis,讀數(shù)據(jù)優(yōu)先到內(nèi)存里讀,讀不到才到 mysql 里讀,大大減少了讀 mysql 的次數(shù)。有了這套組合拳,讀性能輕松上萬 qps。
好了,到這里,我們說的都是我們平時比較容易接觸的開發(fā)場景。
但如果現(xiàn)在我要處理的,不再是上面提到的文本類數(shù)據(jù),而是圖片數(shù)據(jù)。
比如,我有一張帥氣的照片。就下面這張。
每次刷某音聽到有人翻唱蔡健雅的《letting go》的時候,我都忍不住想發(fā)這張圖。
并配文 "還是忘不了"。
那么問題來了。
這張圖片數(shù)據(jù)應(yīng)該存在哪?,又該從哪里讀?
我們回過頭去看 mysql 和 redis 的場景,無非就是存儲層加緩存層。
對于圖片這樣的文件對象,存儲層不太可能再用 mysql,應(yīng)該改用專業(yè)的對象存儲,比如亞馬遜的 S3(Amazon Simple Storage Service,注意后面是三個 S 開頭的單詞,所以叫 s3),或者阿里云的 oss(Object Storage Service)。下面的內(nèi)容,我們就用比較常見的 oss 去做解釋。
而緩存層,也不能繼續(xù)用 redis 了,需要改成使用 CDN(Content Delivery Network,內(nèi)容分發(fā)網(wǎng)絡(luò))。
可以將 CDN 簡單理解為對象存儲對應(yīng)的緩存層。
現(xiàn)在就可以回答上面的提問,對用戶來說,這張圖片數(shù)據(jù)存在了對象存儲那,當(dāng)有需要的時候,會從 CDN 那被讀出來。
CDN 的工作原理
有了 CDN 和對象存儲之后,現(xiàn)在我們來看下他們之間是怎么工作的。
我們平時看到的圖片,可以右鍵復(fù)制查看它的 URL。
會發(fā)現(xiàn)圖片的 URL 長這樣。
https://cdn.xiaobaidebug.top/1667106197000.png
其中前面的 cdn.xiaobaidebug.top 就是 CDN 的域名,后面的 1667106197000.png 是圖片的路徑名。
當(dāng)我們在瀏覽器輸入這個 URL 就會發(fā)起 HTTP GET 請求,然后經(jīng)歷以下過程。
第一階段: 你的電腦會先通過 DNS 協(xié)議獲得 cdn.xiaobaidebug.top 這個域名對應(yīng)的 IP。
?step1 和 step2:先查看瀏覽器緩存,再看操作系統(tǒng)里的 / etc / hosts 緩存,如果都沒有,就會去詢問最近的 DNS 服務(wù)器(比如你房間里的家用路由器)。最近的 DNS 服務(wù)器上有沒有對應(yīng)的緩存,如果有則返回。
?step3:如果最近的 DNS 服務(wù)器上沒有對應(yīng)的緩存,就會去查詢根域,一級域,二級域,三級域服務(wù)器。
?step4:然后,最近的 DNS 服務(wù)器會得到這個 cdn.xiaobaidebug.top 域名的別名(CNAME),比如 cdn.xiaobaidebug.top.w.kunlunaq.com。
? kunlunaq.com 是阿里 CDN 專用的 DNS 調(diào)度系統(tǒng)。
?step5 到 step7:此時最近的 DNS 服務(wù)器會去請求這個 kunlunaq.com,然后返回一個離你最近的 IP 地址返回給你。
第二階段: 對應(yīng)上圖里的 step8。瀏覽器拿著這個 IP 去訪問 cdn 節(jié)點,然后,cdn 節(jié)點返回數(shù)據(jù)。
上面第一階段流程里,提到了很多新的名詞,比如 CNAME,根域,一級域啥的,它們在之前寫的 「DNS 中有哪些值得學(xué)習(xí)的優(yōu)秀設(shè)計」有很詳細(xì)的描述,如果不了解的話可以去看下。
我們知道 DNS 的目的就是通過域名去獲得 IP 地址。
但這只是它的眾多功能之一。
DNS 消息有很多種類型,其中 A 類型,就是用域名去查域名對應(yīng)的 IP 地址。而 CNAME 類型,則是用域名去查這個域名的別名。
對于普通域名,DNS 解析后一般就能直接得到域名對應(yīng)的 IP 地址(又叫 A 類型記錄,A 指 Address)。
比如下面,我用 dig 命令發(fā)出 DNS 請求并打印過程數(shù)據(jù)。
$ dig +trace xiaobaidebug.top ;; ANSWER SECTION: xiaobaidebug.top. 600 IN A 47.102.221.141
可以看到 xiaobaidebug.top 直接解析得到對應(yīng)的 IP 地址 47.102.221.141。
但對于 cdn 域名,一波查詢下來,先得到的卻是一條 CNAME 的記錄 xx.kunlunaq.com,然后 dig 這個 xx.kunlunaq.com 才能得到對應(yīng)的 IP 地址。
$ 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 域名服務(wù)器,它對整個 DNS 體系來說,只是其中一臺小小的 DNS 域名服務(wù)器,看起來就跟其他域名服務(wù)器一樣,平平無奇。DNS 請求也會正常打入這個服務(wù)器里。
但當(dāng)請求真正打到它上面的時候,它的特別之處就體現(xiàn)出來了,當(dāng)查詢請求打入域名服務(wù)器時,普通的 DNS 域名服務(wù)器返回域名對應(yīng)的部分 IP 就夠了,但 CDN 專用的 DNS 域名服務(wù)器卻會要求返回離調(diào)用方 " 最近的 " 服務(wù)器 IP。
怎么知道哪個服務(wù)器 IP 里調(diào)用方最近?
可以看到 "最近" 這個詞其實是加了雙引號的。
CDN 專用的 DNS 域名服務(wù)器其實是 CDN 提供商提供的,比如阿里云當(dāng)然知道自己的的 CDN 節(jié)點有哪些,以及這些 CDN 服務(wù)器目前的負(fù)載情況和響應(yīng)延時甚至權(quán)重啥的,并且也能知道調(diào)用方的 IP 地址是什么,可以通過調(diào)用方的 IP 知道它所屬的運(yùn)營商以及大概所在地,根據(jù)條件篩選出最合適的 CDN 服務(wù)器,這就是所謂的 " 最近 "。
舉個例子。假設(shè)地理位置最近的 CDN 機(jī)房流量較多,響應(yīng)較慢,但地理位置遠(yuǎn)一些的服務(wù)器卻能更好的響應(yīng)當(dāng)前請求,那按理說可能會選擇地理位置遠(yuǎn)一些的那臺 CDN 服務(wù)器。
也就是說,選出來的服務(wù)器不一定在地理位置最近,但一定是當(dāng)前最合適的服務(wù)器。
回源是什么
上面的圖片 URL,是 https://cdn 域名 / 圖片地址.png 的形式。
也就是說這張圖片是訪問 CDN 拿到的。
那么,直接訪問對象存儲能不能拿到圖片數(shù)據(jù)并展示?
比如像下面這樣。
https://oss域名/圖片地址png
這就像問,不走 redis,直接從 mysql 中能不能讀取到文本數(shù)據(jù)并展示一樣。
當(dāng)然能。
我之前放在博客里的圖片就是這么干的。
但這樣成本更高,這里的成本,可以指性能成本,也可以指調(diào)用成本??聪孪旅孢@個圖。
可以看到直接請求 oss 的費(fèi)用差不多是通過 cdn 請求 oss 的兩倍,考慮到家境貧寒,同時也為了讓博客獲取圖片的速度更快,我就接入了 CDN。
但看到這里,問題又又來了。
上面的截圖里,紅框里有個詞叫 " 回源 "。
回源是什么?
當(dāng)我們訪問 https://cdn 域名 / 圖片地址.png 時,請求會打到 cdn 服務(wù)器上面。
但 cdn 服務(wù)器本質(zhì)上就是一層緩存,并不是數(shù)據(jù)源,對象存儲才是數(shù)據(jù)源。
第一次訪問 cdn 獲取某張圖片時,大概率在 cdn 里并沒有這張圖片的數(shù)據(jù),因此需要回到數(shù)據(jù)源那去取出這份圖片數(shù)據(jù)。然后再放到 cdn 上。下次再次訪問 cdn 時,只要緩存不過期,就能命中緩存直接返回,這就不需要再回源。
于是訪問的過程就變成了下面這樣。
那還有哪些情況會發(fā)生回源呢?
除了上面提到的 cdn 上拿不到數(shù)據(jù)會回源站外,還有 cdn 上的緩存過期失效了也會導(dǎo)致回源站。
另外,就算有緩存,且緩存不過期,也可以通過 cdn 提供的開放接口來觸發(fā)主動回源,但這個我們比較少機(jī)會能接觸到。
另外,回源這個事情,其實用戶是感知不到的,因為用戶去讀圖片的時候,只能知道自己讀到了還是讀不到。
同樣是讀到了,還細(xì)分為是從 cdn 那直接讀的,還是 cdn 回源讀對象存儲之后返回的。
那么,我們有辦法判斷是否發(fā)生過回源嗎?
有。我們接著往下看。
怎么判斷是否發(fā)生回源
我們以某里云的對象存儲和 CDN 為例。
假設(shè)我要請求下面這張圖 https://cdn.xiaobaidebug.top/ image / image-20220404094549469.png
為了更方便的查看響應(yīng)數(shù)據(jù)的 http header,我們可以用上 postman。
通過 GET 方法去請求圖片數(shù)據(jù)。
然后通過下面的 tab 切換查看 response header 信息。
此時查看 response header 下的 X-Cache 的值是 MISS TCP_MISS。意思是未命中緩存導(dǎo)致 CDN 回源查 oss,拿到數(shù)據(jù)后再返回。
那此時 CDN 里肯定是有這張圖片的緩存了。我們可以試著再執(zhí)行一次 GET 方法獲取圖片。
X-Cache 的值就變成了 HIT TCP_MEM_HIT,這就是命中緩存了。
這個是某里云的做法,其他比如騰某云啥的,也都大差不差,幾乎都可以從 response header 里找到相關(guān)的信息。
用了 CDN 一定比不用的更快嗎?
看到這里我們就可以回答文章開頭的問題了。
如果沒有接入 CDN,直接訪問源站,流程是這樣的。
但如果接入了 CDN,且 CDN 上沒有緩存數(shù)據(jù),那就會觸發(fā)回源。
相當(dāng)于在原來的流程上還多了一層 CDN 的調(diào)用流程。
也就是,用了 CDN 時,未命中 CDN 緩存導(dǎo)致回源,就會比不用的時候更慢。
未命中緩存,可能是 cdn 里壓根就沒這一數(shù)據(jù),也可能是曾經(jīng)有這條數(shù)據(jù)但后來過期失效了。
這兩種情況都正常,大部分時候并不需要做任何處理。
但對于極個別場景,我們可能需要做些優(yōu)化。比如你們源站數(shù)據(jù)有大版本更新,就像更換 cdn 域名啥的,那在上線的那一刻用戶全用新 cdn 域名去請求圖片啥的,新 CDN 節(jié)點基本上百分百觸發(fā)回源,嚴(yán)重的時候甚至可能會拖垮對象存儲。這時候你可能需要提前將熱點數(shù)據(jù)篩選出來,利用工具預(yù)先請求一波,讓 CDN 加載上熱數(shù)據(jù)緩存。比如某里云上的 CDN 就有這樣的 " 刷新預(yù)熱 " 功能。
當(dāng)然也可以通過灰度發(fā)布的模式,先讓少量用戶體驗新功能,讓這些用戶把 cdn"熱" 起來,然后再逐步放開流量。
還有就是曾經(jīng)有這條數(shù)據(jù)但后來過期失效了,對于熱點數(shù)據(jù),可以適當(dāng)提高一下 cdn 數(shù)據(jù)的緩存時間。
什么情況下不應(yīng)該使用 CDN?
從上面的描述看下來,CDN 最大的優(yōu)勢在于,對于來自世界各地的用戶,它可以就近分配 CDN 節(jié)點獲取數(shù)據(jù),并且多次重復(fù)獲取同一個文件數(shù)據(jù)的時候,有緩存加速的作用。
這對于網(wǎng)頁圖片這樣的場景,是再合適不過了。因為底層用的是對象存儲,也就是說,只要是文件對象,比如視頻啥的,都可以用這套流程接入 cdn 做加速。比如平時刷的某音某手短視頻就是這么干的。
那反過來想想,問題就來了。
什么情況下不應(yīng)該使用 CDN?
如果你有一個公司內(nèi)網(wǎng)的服務(wù),并且服務(wù)請求的圖片等文件不太可能被多次重復(fù)調(diào)用,這時候其實沒必要使用 CDN。
注意上面兩個加粗了的關(guān)鍵點。
? 內(nèi)網(wǎng)服務(wù),是為了保證你是了解服務(wù)的請求來源的,也能拿到對象存儲的讀權(quán)限,并且如果你的對象存儲也是公司內(nèi)部的,那大概率跟你的服務(wù)已經(jīng)在同一個機(jī)房里,這已經(jīng)很近了。接入 CDN 也享受不到 "就近分配 CDN 節(jié)點" 所帶來的好處。
? 圖片或其他文件不太可能被多次重復(fù)使用,如果接入了 CDN,那你每次去訪問 CDN 獲取圖片的時候,CDN 節(jié)點上大概率沒有你要的數(shù)據(jù),相當(dāng)于每次都需要回源到對象存儲去取一把。那接入 CDN 相當(dāng)于給自己加了一層代理,多一層代理,就多一層耗時。
關(guān)于上面的第二點,如果你需要一個明確的指標(biāo)去說服自己,那我可以給你一個。從上面的介紹內(nèi)容,我們知道,可以通過 cdn 響應(yīng)的 http header 中的 X-Cache 字段,看到一個請求是否觸發(fā)過回源,統(tǒng)計次數(shù),再除以總的請求數(shù),就能得到回源的比例,比如回源比例高達(dá) 90%,那還接啥 cdn。
總結(jié)
? 對于文本類數(shù)據(jù)我們習(xí)慣用 mysql 做存儲,redis 做緩存。但屬于文件類數(shù)據(jù),比如視頻圖片,則需要使用 oss 等做對象存儲,cdn 做緩存。
? 用了 CDN 如果發(fā)生回源,那實際上會比不用的時候更慢一些。
? CDN 最大的優(yōu)勢在于,對于來自世界各地的用戶,它可以就近分配 CDN 節(jié)點獲取數(shù)據(jù),并且多次重復(fù)獲取同一個文件數(shù)據(jù)的時候,有緩存加速的作用。如果你的服務(wù)和對象存儲都在內(nèi)網(wǎng),并且文件數(shù)據(jù)也不太會有重復(fù)使用的可能性,那其實沒必要接入 cdn。
本文來自微信公眾號:小白 debug (ID:xiaobaidebug),作者:小白
廣告聲明:文內(nèi)含有的對外跳轉(zhuǎn)鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時間,結(jié)果僅供參考,IT之家所有文章均包含本聲明。