一篇文章讓你搞清楚到底什麼是CDN

2023.11.06

一篇文章讓你搞清楚到底什麼是CDN

當我們打開瀏覽器存取頁面的時候,其實就是一個不斷發送HTTP 請求的過程,客戶端發送HTTP 請求,服務端回傳回應。

當我們打開瀏覽器存取頁面的時候,其實就是一個不斷發送HTTP 請求的過程,客戶端發送HTTP 請求,服務端回傳回應。

這裡的客戶端可以是瀏覽器,也可以是我們使用Python 編寫的程式碼,而服務端則是使用Web 框架編寫的應用程式。

說到這兒,補充一個知識點,很多搞Python 的小夥伴可能分不清WSGI, uwsgi, uWSGI, Nginx 之間的區別,我們來總結一下。

WSGI

WSGI 的全名是Web Server Gateway Interface,即Web 伺服器網關接口,它不是伺服器,也不是Python 模組、框架、或任何軟體,它只是一種描述Web 伺服器和Web 應用程式(使用Web 框架編寫的程式)進行通訊的規範、協定。

基於Web 框架編寫的服務要運行在Web 伺服器上,儘管這些框架本身自帶了一個小型Web 伺服器,但只用於開發和測試。

uWSGI

uWSGI 是一個Web 伺服器,它實作了WSGI, uwsgi, HTTP 等協議,所以我們把使用Web 框架編寫好的服務部署在uWSGI 上面,是可以直接對外提供服務的。

nginx

同樣是一個Web 伺服器,但它相比uWSGI 可以提供更多的功能,例如反向代理、負載平衡、快取靜態資源、對HTTP 請求更加友好,這些都是uWSGI 所不具備、或不擅長的。

所以將Web 服務部署在uWSGI 之後,還要在前面再搭一層Nginx。此時uWSGI 就不再暴露HTTP 服務了,而是暴露TCP 服務,因為它是和Nginx 進行通信,使用TCP 會更快一些,Nginx 來對外暴露HTTP 服務。

軟泥

uwsgi 是Nginx 和uWSGI 通訊所採用的協議,我們說uWSGI 是和Nginx 對接。

Nginx 在接收到使用者請求後,如果請求的是圖片等靜態資源,那麼可以直接回傳。請求的是動態資源,那麼會將請求轉發給uWSGI,然後再由uWSGI 呼叫對應的Web 服務進行處理,處理完畢之後將結果交給Nginx,Nginx 再回傳給客戶端。

而uWSGI 和Nginx 之所以能交互,也正是因為它們都支援uwsgi 協議,Nginx 內部有一個模組叫HttpUwsgiModule,它的作用就是與uWSGI 伺服器互動。

回到正題,我們知道HTTP 是請求-回應模型,當使用瀏覽器開啟一個頁面時,瀏覽器和目標伺服器就是HTTP 協定的兩個端點。

那麼問題來了,瀏覽器發出的請求,一定要直接到達指定的目標伺服器嗎?可不可以在其它地方先逗留一下呢?答案是可以的,這個地方就是代理。

在 HTTP 協定中,代理程式(Proxy)是請求方和應答方中間的一個環節。作為中轉站,既可以轉發客戶端的請求,也可以轉發伺服器的應答。代理的種類很多,常見的有:

  • 匿名代理:完全隱匿了被代理的機器,外界看到的只是代理伺服器
  • 透明代理:顧名思義,它在傳輸過程中是透明開放的,外界既知道代理,也知道客戶端
  • 正向代理:靠近客戶端,代表客戶端向伺服器發送請求
  • 反向代理:靠近伺服器,代表伺服器向客戶端回傳回應

關於正向代理和反向代理,我們再舉兩個例子來解釋。

正向代理

假設你想找B 借一樣東西,但B 不同意,所以你拜託A 去跟B 借,然後再交給你。這裡的A 就扮演了代理的角色,也是正向代理,因為真正找B 借東西的是A。

如果A 在找B 借東西的時候沒有說這是你想藉的,那麼A 就是匿名代理,因為B 不知道你的存在;如果A 告訴了B,其實是你拜託他來找B 的,那麼A就是透明代理,B 知道A,同時也知道你。

像我們平常掛的 V批N 就是正向代理,當你訪問谷歌卻慘遭拒絕時,你可以讓 V批N 去幫你訪問。而對於Google而言,向它發送請求的是 V批N,不是你。

反向代理

反向代理也很簡單,例如存取百度,其背後可能有千千萬萬台伺服器在提供服務,但我們不會直接存取它們,而是存取反向代理伺服器。

www.baidu.com 所在的是代理伺服器,它會幫我們把請求轉送到真實的伺服器那裡去。像Nginx 就是一個非常好的反向代理伺服器,可以對背後所有真實的伺服器進行一個權衡,將請求轉發到一個合適的伺服器上,也就是所謂的負載平衡。

再例如小明同學聯絡老鴇,希望她能提供一個小姐姐上門幫忙補習外語,這個老鴇就是反向代理,她會將小明的請求轉發到某一個小姐姐那裡去。

所以正向代理和反向代理都屬於代理,而核心差異就在於代理的對像不同:正向代理代理的是客戶端,負責向服務端發送請求;反向代理代理的是服務端,負責向客戶端返迴響應。

由於代理在傳輸過程中插入了一個中間層,因此可以在這個環節做很多有趣的事情,例如:

  • 負載平衡:把存取的請求均勻分散到多台機器,實現存取叢集化
  • 內容快取:暫存上下行的數據,減輕後端的壓力
  • 安全防護:隱性IP,使用WAF 等工具抵禦網路攻擊,保護被代理的機器
  • 資料處理:提供壓縮、加密等額外的功能

了解了以上內容,就能很清楚知道什麼是CDN 了。

CDN 的全稱為 Content Delivery Network,翻譯過來就是內容分發網絡,它應用了HTTP 協定裡的快取和代理技術,取代源站伺服器回應客戶端的請求。所以 CDN 也屬於代理,通常扮演透明代理和反向代理的角色。

說穿了就是它可以快取源站的數據,讓瀏覽器的請求不用千里迢迢地到達源站伺服器,直接在半路就可以取得回應。如果CDN 的調度演算法很優秀,那麼就可以找到離用戶最近的節點,大幅縮短回應時間。

因為在現如今這個資訊量爆炸的時代,使用者等待的耐心也越來越低,有一個說法:當使用者開啟一個頁面,如果超過4 秒沒有回應,他就會關閉這個頁面。所以任何一個服務供應商,都希望自己服務的回應速度夠快,這樣才能留住使用者。

而使用者從發出請求到接收回應所消耗的時間不僅取決於網路頻寬,還取決於傳輸距離。例如伺服器在廣東,但存取的用戶在北京,地理位置的距離會導致延遲變得明顯,而且傳輸距離過長也會導致封包遺失可能性變大,導致網路中斷。

所以CDN 便誕生了,它是專門負責解決長距離導致網路存取速度慢的一種應用服務。其最初的核心理念就是將內容緩存在終端用戶附近,源站不是離用戶遠嗎,沒關係,在靠近用戶的地方建立一個緩存伺服器,將源站的內容拷貝一份放在這裡不就行了。

後續北京的用戶訪問北京的快取伺服器,上海用戶訪問上海的快取伺服器。沒錯,這便是CDN 的核心思想,只是建立快取伺服器需要大量資金,很多公司通常不會自己這麼幹,而是購買現有的CDN 服務。

有許多CDN 廠商投入了大筆資金,在全國、乃至全球的各個大樞紐城市都建立了機房,部署了大量擁有高儲存高頻寬的節點,建構了一個專用網路。這個網絡是跨運營商、跨地域的,雖然內部也劃分成多個小網絡,但它們之間用高速專有線路連接,是真正的信息高速公路,基本上可以認為不存在網絡擁堵。

有了高速的網路傳輸通道後,CDN 就要分發源站的內容了,採用快取代理技術,使用推或拉的手段,將源站的內容逐級緩存到網路的每個節點上。由於整個過程相當於透過網路對內容做了分發,因此叫CDN,即內容分發網路。

具體來說,CDN 是採用更多的快取伺服器(也叫CDN 節點),當使用者造訪網站時,利用全域負載技術,將使用者的請求轉送到距離最近的CDN 節點(術語叫做邊緣節點)上,由快取伺服器響應用戶請求。這樣一來就省去了長途跋涉的時間成本,實現了網路加速。

那麼CDN 都能加速什麼樣的內容呢?或者說CDN 節點該保存哪些內容呢?

在CDN 領域,內容其實就是HTTP 協定裡的資源,像是超文本、圖片、影片等。資源依照是否可以緩存,分為靜態資源和動態資源兩類。

  • 靜態資源:資料內容靜態不變,任何時候來存取都是一樣的,例如圖片、音訊。
  • 動態資源:資料內容動態變化,即內容由後台服務計算生成,每次存取都可能發生變化,例如商品的庫存、微博的粉絲數等。

很顯然,只有靜態資源才能夠被快取加速、就近訪問,而動態資源只能由來源站即時生成,即使快取了也沒有意義。不過,如果動態資源在一段時間內不會發生變化,那麼可以在回應頭中指定Cache-Control 字段,表示允許快取一段短暫的時間,那麼它在這段時間內也就變成了靜態資源,可以被CDN 快取加速。

CDN:我們不生產內容,我們只做內容的搬運工。

到目前為止,我們已經知道CDN 到底是啥了,然後再來看看它是如何運作的。CDN 有兩個關鍵組成部分:全域負載平衡和快取系統。

全域負載平衡

全域負載平衡(Global Sever Load Balance)一般簡稱為GSLB,它是CDN 的大腦。主要的職責是當用戶接入網路的時候,在CDN 專網中挑選出一個最佳節點提供服務,解決的是如何找到最近的節點,即邊緣節點,負責對整個CDN 網路進行負載平衡。

GSLB 最常見的實作方式是DNS 負載平衡,不過GSLB 的方式要稍微複雜一些。

首先在沒有CDN 的時候,權威DNS 回傳的就是來源站伺服器的實際IP 位址,瀏覽器收到DNS 解析結果後直連即可。但加入CDN 就不一樣了,權威DNS 回傳的不再是IP 位址,而是一個CNAME(Canonical Name)別名記錄,指向的就是CDN 的GSLB。

意思就是我沒辦法給你來源站伺服器的IP,給你的是GSLB,你需要再去GSLB 查一下。因為沒拿到IP 位址,於是本地DNS 就會向GSLB 再發起請求,這樣就進入了CDN 的全域負載平衡系統,基於以下原則開始智慧調度:

  • 看用戶的IP 位址,查表得知地理位置,找相對最近的邊緣節點。例如IP 是北京,那就找北京的邊緣節點;
  • 看用戶所在的電信商網絡,找相同網路的邊緣節點,因為邊緣節點不只一個,但選擇網路相同的更有優勢;
  • 檢查邊緣節點的負載狀況,找出負載較輕的節點;
  • 參考節點的健康狀況、服務能力、頻寬、回應時間等;

GSLB 把這些因素綜合起來,用一個複雜的演算法,最後找出一台最適合的邊緣節點,把這個節點的IP 位址回傳給用戶,用戶就可以就近訪問CDN 的快取代理了。

快取系統

快取系統是CDN 的另一個關鍵組成部分,相當於CDN 的心臟。如果快取系統的服務能力不夠,不能很好地滿足使用者的需求,那麼GSLB 調度演算法再優秀也沒有用。

但網路上的資源是無窮無盡的,不管CDN 廠商有多大的實力,都不可能把所有資源都緩存起來。所以,快取系統只能選擇性地快取那些最常用的資源,於是就產生了CDN 中的兩個關鍵概念:命中和回源。

命中就是指使用者存取的資源恰好在快取系統裡,可以直接回傳給使用者。回源則相反,快取裡沒有,代理必須先將資料從來源站同步過來。

對應的,衡量CND 服務品質的兩個指標便是命中率和回源率,計算方式為命中次數 / 回源次數除以總訪問次數。顯然,好的CDN 應該是命中率越高越好,回源率越低越好。現在的商業CDN 命中率都在90% 以上,相當於把源站的服務能力放大了10 倍以上。

那要如何才能盡可能地提高命中率、降低迴源率呢?

首先肯定是在儲存系統上下功夫,盡可能儲存更多的內容。

其次,快取也可以劃分層級,分為一級快取和二級快取。一級快取配置高一些,直連源站,二級快取配置低一些,直連用戶。回源的時候,二級快取只找一級緩存,一級快取沒有再回源。這樣扇入便縮小了,可以有效地減少回源。

CDN 雖然有很多的優點,但它不是萬能的。

如果是用戶動態互動的即時數據,那麼很難緩存在CDN 中。

另外很多公司為了保護自身的資料隱私,不允許第三方CDN 廠商快取數據,只允許自家CDN 緩存,這個可能會造成一些影響。

然後就是最關鍵的,如果是自建CDN,那麼非常燒錢,因此大部分公司都不會自建,而是選擇專門的CDN 廠商。但即便租用CDN 服務,花的錢也不少,區域越多花的錢也越多。

CDN 和邊緣運算

網路公司採用CDN 是用儲存空間換網路低延遲,但許多通訊公司也青睞CDN,目的則是以儲存空間換網路頻寬。透過服務下沉,減輕上層骨幹網路的流量壓力,避免硬體擴容,降低網路建置成本。因為大量的業務流量資料在骨幹網路跑來跑去,骨幹網路肯定吃不消,要拼命擴容。但如果這些業務流量資料在底層就解決了,那麼骨幹網路的頻寬壓力自然就減輕了。

許多業者已經將CDN 下沉到地市級,以此減輕壓力,同時可以提升使用者體驗。說到這,你應該想到了邊緣運算,有很多人覺得CDN 和邊緣運算很相似,因為CDN 算是邊緣運算的雛形。

一直以來,隨著網路能力的不斷提升,內容資源和運算能力都在不斷往上走,走到雲端運算中心。透過核心的雲端運算中心,對所有終端節點提供服務。但隨著使用者量的增加,使用者所在區域和運算中心可能距離很遠,那麼不管把計算中心設置在什麼地方,也不管它的能力有多強大,都無法克服物理距離上的障礙。

於是人們便想到,資料能不能不要上傳到運算中心,而是轉移到網路的邊緣,也就是資料輸入的地方(例如IoT 設備),然後直接計算呢?於是便有了邊緣運算,它不會將資料傳送到運算中心處理,而是在資料來源附近處理資料。

所以CDN 和邊緣運算還是有差異的:

  • CDN 負責優化資料交付;邊緣運算負責優化資料處理
  • CDN 通常用於互動靜態內容,例如網頁、圖片和視訊;邊緣運算用於需要快速資料處理的應用,例如即時資料分析等
  • CDN 會將內容放到距離使用者近的地方;邊緣運算會將運算和資料處理放到盡可能靠近資料產生的地方

但這兩者是可以互補的,例如一個邊緣運算設備可以使用CDN 來有效率地互動內容,同時在網路邊緣處理資料。

另外CDN 也可以使用邊緣運算,透過把運算動態資源的程式碼和資料也放在CDN 的節點上,這樣就可以在CDN 裡取得動態資源不用回源了。