什么是 CDN?
![]() ![]()
Origin Server: 源站,也就是做 CDN 之前的客戶真正的服務器;
User: 訪問者,也就是要訪問網站的網民;
Edge Server: CDN 的服務器,不單只“邊緣服務器”,這個之后細說;
Last Mile: 最后一公里,也就是網民到他所訪問到的 CDN 服務器之間的路徑。
|
舉例:
我們平時所使用的DNS服務器,一般稱之為LDNS,在解析一個域名的時候,一般有兩個情況,一種是域名在DNS上有記錄,另一種情況是沒有記錄,兩種情況的處理流程不一樣。
當你訪問163這個域名時,如果LDNS上有緩存記錄,那它會直接將IP地址直接給你。如果沒有緩存記錄,它將會一步步向后面的服務器做請求,然后將所有數據進行匯總交給最終的客戶。
當你訪問163這個地址時,實際上如果本身沒有內容的話,它要去后面拿數據,這個過程術語叫遞歸,它首先會向全球13個根域服務器請求,問com域名在哪,然后根域服務器作出回答,一步步往下。
|
DNS調度
是如何進行調度和進行定位的?
![]() ![]()
其實也是通過LDNS的具體地址來進行的,比如,看圖,假設你是一個廣東電信客戶,那你所使用的DNS服務器去做遞歸的時會訪問到某一個CDN廠商的GRB,全球的一個調度系統,他就能看到來自於哪個LDNS。假設如果用戶和LDNS使用同一個區域的服務器,他就會間接認為用戶也是廣東電信的。
再舉個例子,比如說北京聯通的用戶,它使用DNS地址,一般自動給它分配的是北京聯通的服務器,這個服務器去做遞歸的時候,調度服務器就會看到這個請求是來自北京聯通的LDNS服務器,就會給它分配一個北京聯通的服務器地址,然后讓來自北京聯通的用戶直接訪問北京聯通的服務器地址,這樣來實現精准的區域性調度。
總結:用戶在設置本身DNS上需要警惕,不同的DNS指向的地區不同,會嚴重影響速度。
|
Http的302調度:
在http協議中有一個叫302跳轉的功能,它的實現並不是說你訪問一個URL,然后馬上吐給你想要的數據,而是吐給你一個302返回信令,這個信令頭部會告訴你,有一個location目標,這個location就是告訴你下一步將要怎么做,而具體調度是通過location來實現的。
![]() ![]()
舉例:即便我所使用的DNS和我不在一個區域,但當我訪問http server的時,這個server是由CDN公司提供的。客戶訪問server的時,雖說通過DNS方式無法拿到客戶的真正IP地址,但是如果你訪問的是http server,他一定能直接看到客戶的真實IP,利用這種方法可以進行調度的糾偏,可以直接返回給你一個302,然后location里面攜帶一個真正離你最近的CDN server。
這種調度方式,優勢是准確,但是也存在弊端,它不像DNS那樣直接請求一個數據包過去給一個反饋就OK了,他需要一次TCP的三次握手建連。
|
存在的問題:
一般情況下都是通過DNS來進行第一次調度,然后用http來進行第二次糾偏。這種情況下大家可以想象,如果你下載一個大文件,比如說電影,但你訪問的是一個頁面小元素,比如說這個圖片只有幾k,那么,實際上你調度的時間就已占用了很大的成分。實際上,這種302調度是一種磨刀不誤砍柴工的方案,如果你后面有很多工作要做,比如要下載一個電影時間會很長,那你調度准確,即使花一點時間調度也是值得的。但是如果你后續訪問一下就完了,那么你這樣調度就沒有太大意義。
|
Http DNS調度:
![]() ![]()
原理是通過一個正常的http請求,發一個get的請求,然后再請求里面以參數的形式攜帶一個目標解析的域名,然后服務器那邊去通過數據庫查詢,查詢之后又通過http的正常響應,把目標請求的IP通過http協議給用戶,這種協議有一個特點就是必須雙端都支持,因為這種模式是非標准的。
這有點類似是一種API的這種方式,那如果要實現的話就必須雙端都支持。
一般,第三種調度的應用場景是在手機的APP端,在APP軟件里面,你要訪問某些東西很有可能被運營商劫持等問題。那為了避免這種劫持,可能會用到這種http DNS的調度方式。
|
CDN的接入:
那在沒有CDN之前,返回給用戶的IP地址就是在原來沒做CDN時的原始服務器地址。但如果你做過CDN的話,你會發現最終拿到的這個IP地址是CDN的節點,而並不是真正的原始服務器。
![]() ![]()
實際上第一跳是跳到網速地址,第二跳是分配了網速的一個平台,這個平台又分開其他的IP給最終的客戶。
|
Cache 系統
在CDN里還有一個非常大的重頭戲就是Cache系統,也就是緩存系統。它用於把那些可以緩存住的東西,緩存到CDN的邊緣節點,這樣當第二個人去訪問同一節點,同一具體電影或MP3時就不用再經過CDN鏈路回到真正的源站去拿數據,而是由邊緣節點直接給數據。
|
對於Cache系統來說,有兩種不同的工作狀態。
第一種工作狀態就是所謂的命中(hit),第二種就是沒有命中(miss)。如果命中了,直接通過檢索找到磁盤或內存上的數據,把這個數據直接吐給客戶,而不是從后面去拿數據。這樣的話就起到一個很完美的加速效果。
第二種是在miss時,其實,miss的時候跟hit唯一的區別就是,當我發現我的本機上沒有這個資源,我會去我的upstream(上游)去拿數據。拿完這個數據,除了第一時間給客戶,同時還會在硬盤上緩存一份。如果這個硬盤空間滿了,會通過一系列置換方法,把最老的數據、最冷的數據替換出去。
|
安全問題
攻擊一般分成兩種,第一種叫
蠻力型攻擊,量大的讓你的帶寬無法抗住最后導致拒絕服務,另外一種是
技巧性攻擊。
蠻力型攻擊,作為CDN來講,就已經將你的原始服務器的IP進行了隱藏。這樣當一個攻擊者去訪問你的域名的時,實際上訪問的並不是你真正的服務器。當他訪問的是CDN的節點,就沒有辦法把CDN的節點打倒,換句話說,即使有能力把CDN的比如10g的節點或者是40g的大節點全部打倒,但由於CDN天然的分布式的部署方式,他也很難在同一時間之內迅速的把全國所有CDN的邊緣節點全都打癱。
技巧型攻擊,比如說,像注入、掛馬甚至說更嚴重的會直接拖走你的數據庫等等。防范:如WAF,就是應用層防火牆,他可以直接去解析你的請求內容,分析內容是否有惡意性,如有惡意性的話去進行過濾,報警等一系列措施來保證你的原始服務器的安全。
|
CDN核心
原始的CDN其實是Content Delivery Network這三個詞的縮寫,也就是內容分發網絡。CDN的理念是加速,所以,我們就盡一切可能去做各種優化,從一層到七層的優化來實現最終的優化效果。
![]() |

具體優化:
一層優化硬件,服務器選型就是一種優化。是用ssd,還是用saker硬盤,CPU應該用至強還是應該用阿童木的等等。
至於二層,鏈路層的優化指的就是資源方面。比如機房如何去選擇。
三層路由層是指你在middlemell這塊真正選路的具體的細節,后面會有一個圖來具體講一下。
四層是指傳輸層的優化,我們一般的業務全都是TCP,所以說這里面就可以明確的說這里是指TCP的優化。
七層也是可以優化的。比如說你強行對內容進行壓縮,甚至你改變壓縮級別去
在現今的互聯網里,TCP優化是可以帶來最直接客戶體驗感的一種實現方式。
![]() |

為什么沒有對手快分析:
在CDN里你玩的是什么?你玩的實際上就是網絡。對CDN公司來說。坦白來講,服務器有三大部分組成,第一部分是你的操作系統,第二部分是你的Cache緩存系統,第三部分就是你的網絡。
一般你的操作系統選型完畢優化之后你一般不會再動它了,除非遇到了重大的安全隱患或者是有重大的升級。而對你Cache系統來說也是,一般都求穩,在沒有重大的bug的時,不會去輕易的改變。但最復雜的就是網絡,你必須要掌握對網絡的控制度,這樣的話你才能駕馭它。
|

RTT: 往返時延。表示從發送端發送數據開始,到發送端收到來自接收端的確認,總共經歷的時延。
我們可以通過第一次和第二次握手,看到他的往返時延是35毫秒。和之前的23毫秒相比,可知這個資源的ping值比原來增加了52%。通過剛才的分析方法我們也可以找到第35和37號包的跳變點。那么35號包之前是第一個發送輪回。整個的發包數量是20,它的初始發包數量實際上並不是標准的10,而是20。那么,我們可以再算一下,如果你有50kb必須要發出,你最終需要也是36個包,但是你初始是20就需兩輪,分別是20+16。
通過套公式,可知需要150毫秒完成。那150毫秒跟之前的92比只慢14%。在資源落后52%的情況下,最終效果才慢了14%,中間的這個差距實際上就是你的技術帶來的價值。
|
WScale、SACK是什么東西?
每個廠商無論你是做CDN,做電商、做IT企業,只要你有對外提供的server,而且server的負載比較高都會遇到的一個syncookie的坑。在TCP的標准里有兩個選項一個叫WScale一個是SACK。

在TCP三次握手的時候,客戶端如果要支持WScale選項的話,服務端被通知支持這個選項。如果服務端也支持,會記錄下來說客戶端支持,同時回應也支持。在客戶端拿到第二次握手時,服務端就也把自己置成支持狀態了。在數據傳輸的時,它是以2為底數,然后以WScale的這個n值為指數的一個滑動窗口遞增值。
利用這個WScale是可把發送窗口的數量漲到很大的,比如說64k、128k、256k甚至更大。如果要這樣再套公式,他的傳輸效果就會變得非常好了。
|
關於參數SACK,選擇性應答。在你數據傳輸的時,沒有這個選項會怎么樣呢?比如,要傳10個數據包,只有第6個數據包丟掉了,這時候需要把6到10重新發一遍,存在許多重復提交,速度會非常慢。
如果收到連續的序號完整的到5,但是還收到了7到10。服務端就可通過這兩個信息進行拼接找到中間的空隙,就會知道只有6號丟掉了,只需傳6即可。
|
syncookie需要注意的坑!
syncookie開啟的情況下會怎么樣呢?他會在協議棧之前自己偽造一個應答機制,並不是真正的協議棧去代應答第二次握手。同時他的第二次握手會攜帶一個算好的一個cookie值作為第三次握手的校驗。如果他收到了第三次握手的校驗值的會被認為是一個合法的建連,那么,他會把這個通過注入的方式,直接告訴你這個鏈接可以直接用了。那在前期syncookie當滿的時候開始啟動這個狀態,他是不占用隊列的,所以說他是一個非常好的防攻擊的一個手段,但是他的防攻擊的量不會很大,微量是可以的。
但坑也恰恰就在這。由於syncookie他不是標准的TCP協議棧,所以說他的支持,並不是非常的完備。等一段syncookie發出,他代應答的第二次握手並不攜帶WScale和SACK這個選項。就會讓客戶端誤認為是不支持的,所以,后續的溝通就變得非常的低效。我們之前做過一個實驗,在有一定量丟包而且大延時的情況下,你的速度可能只有300多k。后來查了很多資料發現確實是這個樣子,而且我們做了很多的模擬時間。比如,都為syncookie出發的時,他速度確實就很快。
后來我們做了一個改動,在syncookie上,如果要是代應答的時,我們攜帶SACK的這個數據給客戶,那后來建連的時都可以把這個功能用起來。用起來時我們在線上是真正的無環境試驗可以提升大概25%到35%的服務質量。
|
Cache的選型
目前市場上常用的cache選型:
![]()
很多公司直接使用開源; 目前並不推薦自研
原因:
第一,你要耗費大量的人力和時間。
第二,你需要去思考,你能不能cover住這些原本人家已經做好的東西。
![]()
通過上面的截圖分析: 在客戶端發起請求的時候期望去和服務器進行這種長連接。而服務器給出去的時,並沒有明確的告訴客戶端是否支持。
導致這個問題的原因是由於我們的研發人員並沒有真正地領會RTT協議的精髓,他沒有完全cover住這個RTT協議導致最基本的這種車輪,這個輪骨做的是有問題的導致很嚴重的坑。
|
轉自《https://mp.weixin.qq.com/s?__biz=MjM5NTU2MTQwNA==&mid=2650653458&idx=3&sn=b658019ef6407a7d00f784f6f0cf238f&chksm=beffc9c1898840d7b75b27a3ba1f0f3084f6f7d7a45789c4adfbdf99522c15197d3974f88666&scene=21#wechat_redirect》,整理發布。