大規模網站架構的快取機制和幾何分形學

徐漢彬發表於2015-09-29

快取機制在我們的實際研發工作中,被極其廣泛地應用,通過這些快取機制來提升系統互動的效率。簡單的總結來說,就是在兩個環節或者系統之間,會引入一個cache/buffer做為提升整體效率的角色。

而 有趣的是,這種快取機制令人驚奇並且優美的遵循著“幾何分形”的規律,也就是幾何分形學中的“自相似性”:從整體上看遵循某種組成規律或者特性,同時從每 一個區域性看,仍然遵循某種組成的規律或者特性。我們的這些系統,從整體上看遵循了快取機制,每一個組成的區域性也遵循快取機制。

等同類比的一個概念,我們常常說的“空間換時間”,犧牲一部分空間代價,來換取整體效率的提升。

例如A和B兩者之間的資料交換,為了提升整體的效率,引入角色C,而C被用於當做熱點資料的儲存,或者是某種中間處理的機制。

我們先從web前端層面開始,看看有哪些比較關鍵的快取機制?它們又是怎樣協調工作的呢?

一、前端Cache機制

1. 域名轉為IP地址(域名伺服器DNS快取)

我們知道域名其實只是一個別名,真實的伺服器請求地址,實際上是一個IP地址。獲得IP地址的方式,就是查詢DNS對映表。雖然這是一個非常簡單的查詢, 但如果每次使用者訪問一個url都去查詢DNS一次,未免顯得太頻繁,會產生一個可怕的訪問量級。DNS伺服器會告訴你,你別老是經常過來,萬一我掛了,我們就無法愉快地玩耍了。

各個瀏覽器的快取時間,會有一定的差別。例如,在chrome瀏覽器中檢視dns的快取時間的方式是:chrome://net-internals/#dns。

瀏覽器一般會在本地會建立一個DNS快取,在一段比較長的時間裡,都是使用本地的快取對映。例如,在Win7系統的cmd裡,可以通過“ipconfig /flushdns ”的方式來立刻重新整理本地DNS。

優點:域名對映為IP非常快。

成本:消耗一定的瀏覽器空間來儲存對映關係

2. 訪問伺服器,獲取靜態內容(地理位置分散式服務CDN)

可能有人會覺得,這個CDN不是快取。其實,CDN的原理就是將離你很遠的東西,放在離你很近的地方,通過這種方式提高使用者的訪問速度。從這個角 度,它也可以理解為犧牲空間成本換取了時間,本質上也是一種特殊的中間cache。騰訊、阿里等這些大的一線網際網路公司一般傾向於自己建立CDN系統,中 小型企業也經常使用第三方的CDN服務。

優點:解決使用者離伺服器太遠的時候,網路路由中跳來跳去的嚴重耗時。

成本:全國各地部署多套靜態儲存服務,管理成本比較高,釋出新檔案的時候,需要等待全國節點的更新等。

3. 瀏覽器本地快取(無網路互動型別)

在前端優化原則中,其中一條就是儘量消滅請求,以達到降低伺服器壓力和提升使用者體驗的效果。靜態檔案,例如Js、html、css、圖片等內容,很多內容可以1次請求,然後未來就直接訪問本地,不再請求web伺服器。

常用的實現方法是通過Http協議頭中的expire和max-age來控制,這兩者的使用方法和區別,我這裡就不贅敘了。還有一種HTML5中很熱的方式,則是localStorage,尤其在移動端也被做為一個強大的快取,甚至當做一種本地儲存來廣泛使用。

優點:減少網路傳輸,加快頁面內容展示速度,提升使用者體驗。

成本:佔用客戶端的部分記憶體和磁碟,影響實時性。

4. 瀏覽器和web服務協議快取(有網路互動型別)

瀏覽器的本地快取是存在過期時間的,一旦過期,就必須重新向伺服器請求。這個時候,會有兩種情形:

伺服器的檔案或者內容沒有更新,可以繼續使用瀏覽器本地快取。

伺服器的檔案或者內容已經更新,需要重新請求,通過網路傳輸新的檔案或者內容。

這裡的協商方式也可以通過Http協議來控制,Last-Modified和Etag,這個時候請求伺服器,如果是內容沒有發生變更的情況,伺服器會返回 304 Not Modified。這樣的話,就不需要每次訪問伺服器都通過網路傳輸一個比較大的檔案或者資料包,只要簡單的http應答就可以達到相同的請求檔案效果。


下圖中的例子,是騰訊的自建CDN(imgcache.gtime.cn):

優點:減少頻繁的網路大資料包傳輸,節約頻寬,提升使用者體驗。

成本:增加了伺服器處理的步驟,消耗更多的CPU資源。

5. 瀏覽器中間代理

上面的幾種cache機制,實際上都是非常常見。但是,在移動網際網路時代,流量昂貴是很多使用者心中深深的痛。於是,又出現了一種新型的中間cache, 也就是在瀏覽器和web伺服器再架設一箇中間代理。這個代理伺服器會幫助手機瀏覽器去請求web頁面,然後將web頁面進行處理和壓縮(例如壓縮檔案和圖片),使頁面變小,然後再傳輸給手機端的瀏覽器。


部分手機瀏覽器(例如Chrome)號稱可以節省流量,提升訪問速度,實際上就是上述做法。但是,也分為兩種情況:

  • 使用者的網路和手機配置都比較差,因為頁面被壓縮變小,載入和傳輸速度變快,並且節約了流量。
  • 使用者的網路和手機配置都比較好,本身直連速度已經很快了,反而因為設定了中間代理,載入速度變慢,也可節約流量。

下圖是chrome手機瀏覽器中,開啟和不開啟中間代理的對比圖:

優點:節約使用者流量,大部分情況下提升了載入速度。

成本:需要架設中間代理伺服器,對各種檔案進行壓縮,有比較高的伺服器維護成本。

6. 預載入快取機制

這種載入方式主要流行在移動端,為了解決手機網速慢和瀏覽器載入效能問題,瀏覽器會判斷頁面的關聯內容,進行“預載入”。 也就是說,在使用者瀏覽A頁面的時候,就提前下載並且載入B頁面的內容。給使用者的體驗就是,B頁面一瞬間就出現了,中間沒有任何延遲的感覺,從而帶來更好的 極佳的使用者體驗。

這種實現機制,往往由瀏覽器來實現,當然,手機頁面本身,也可以通過JS來自身實現。而這種機制也存在一些問題,瀏覽器需要預判使用者的瀏覽行為,在一些場景下,這個預判演算法本身不一定準確,如果不準確則帶來一定的流量、記憶體和系統資源的浪費。

優點:給使用者帶來極佳的頁面展示體驗。

缺點:預判實現比較複雜,佔據一定的記憶體和手機系統資源,可能產生流量和資源浪費。

前端的cache當然不僅僅如此簡單,如果細緻到每一個小環節和組成部分,我們會發現實際上是無處不在的,例如瀏覽器的渲染行為、網路網路卡的傳輸環節,小環節和小環節之間也有無數這種型別的cache角色。

這個就如同幾何分形學中的自相似性:從整體上看符合某種組成規律或者特性,同時,從區域性看,仍然符合某種組成的規律或者特性。

幾何分形的現象在我們生活中,也是非常常見的,例如:

人體中的幾何分形例子,例如:人體有1個頭部+4肢,區域性上看人的手指也是1個手指頭+4個手指;人體無論整體或者區域性,都大致遵循黃金分割點0.618的比例來生長(五官按照這個比例越多,越好看)。

例如下圖中的葉子,每個區域性都和主幹組成結構相似。

二、Web系統和幾何分形學

1. Web系統中的快取機制

看完上面的前端cache,我們會感覺到快取機制在前端中的確無處不在,那麼它在其他地方和環節,是否也無處不在?

可以看看這張圖:

實際上,每一個環節本身是可以又再次被放大的,放大以後,我們又看見了更多快取機制的“特性”存在。從一個整體來看,符合該規律,從組成部分來看,仍然符合該規律。

每一個組成快取機制的“成員”的內部,又存在著更多的快取機制。

Apache內部的一些“快取機制”:

  • url對映快取mod_cache(有mode_disk_cache和mod_mem_cache,後者官方已不推薦)
  • 快取熱點檔案開啟描述符mod_file_cache(對於靜態檔案的情況,減少開啟檔案中open行為的耗時)
  • 啟動的時候,通過prefork模式設定的StartServers服務程式池,犧牲記憶體空間。

MySQL內的一些“快取機制”:

  • 資料庫的索引,犧牲磁碟空間(組合索引等會佔據很大的磁碟空間)
  • innodb_buffer_pool_size,熱點資料的快取,犧牲記憶體空間
  • innodb_flush_method寫入磁碟的機制,可以配置成緩衝寫入的方式
  • query_cache_size查詢快取,犧牲記憶體空間
  • thread_cache_size資料庫連線池的快取個數,犧牲記憶體空間

2. 接近硬體層面的“空間換時間”

那我們再來看更細小的一個環節,計算機寫的操作。我們會發現,在記憶體和物理磁碟之間,還有一個磁碟緩衝區(頁快取記憶體)的存在,這個是記憶體和磁碟之間的“快取”。當然,讀取的操作也是同理。

下圖是“放大”MySQL中的寫入磁碟:

實際上,更進一步看,CPU和記憶體之間也存在快取機制(常用指令會存在放在暫存器中,因為CPU訪問暫存器會遠快於訪問記憶體,中間為了緩衝它們之間差距,設定了多級快取記憶體)。

例如下圖是Intel i7 920的各級快取大小:

這個時候,我們可以看出來,計算機系統從大的系統層面看,是遵循“快取機制”的規律的,同時,在每個區域性成員的層面,同樣遵循該規律。

3. 現實世界中的“快取機制”

我們現在喝水通常使用的是杯子,杯子實際上也扮演著一個特殊的Cache角色。舉個例子:一個人離飲水機比較遠,他渴了,他有如下兩種“喝水”的方式:

  • 不用杯子,每次渴了直接去飲水機喝(這個比較霸氣側漏,不要在意細節)。結果:頻繁跑動,耗費體力。
  • 使用杯子,渴了先喝杯子(Cache)上的水,如果杯子沒有,帶上杯子去裝水,再喝。結果:比較少跑動,節省體力。

這樣看不直觀,簡化為一個流程圖如下:

這雖然是個人盡皆知的道理,但是,這個方法本身是“進化”出來的。百萬年前的原始人類和其他大自然的動物一樣的,喝水遵循了第一種方式,只是隨著人類的發展,“進化”出第二種喝水的方式。

這裡也存在一個快取機制,就是用杯子的空間獲取喝水效率的時間。

還有一個更為典型的例子,就是坐車/運輸,假設我們從深圳去廣州,我們會去坐客運車。而客運車(假設上面有40個 座位)實際上相當於一個40個座位的“佇列”。遵循著網路傳輸的相同的規律“佇列滿或者超時則傳送”。客車本身的40個位置,就像一個“傳送緩衝區”。使 用和不使用這個大的緩衝區,客車也可以有兩者運作方式:

  1. 車站發現來一個人,用只能容納一個人的小車,不等待直接送一個人去廣州。
  2. 車站發現來一個人,先放進客車buffer中,等待人滿或者達到班車約定時間(佇列超時)再出發。

顯而易見,第一種是太浪費資源了。

除此之外,還有很多各種各樣的例子,如江河上的大壩、我們桌面上的一些東西(它們佔據寶貴的桌面空間)、我們公司附近小店裡的商品、離我們近的東西等等。

看到這裡,很多人會漸漸發覺,計算機的一些原理,竟然在現實世界裡有無處不在的“對映和影子”。

幾何分形學是個非常有趣的東西,某些規律,實際上還貫穿在整個巨集觀和微觀世界中。

例如“繞轉”的現象:


4. 現實世界和計算機“快取機制”原理的關係,為什麼遵循“幾何分形”?

實際上,計算機的原理來源於數學,而數學是日常生活現象和規律的高度抽象,源於生活,高於生活。

同時,不僅僅“快取機制”,還有很多其他技術的原理,也能找到這種遵循“幾何分形學”的樣子。

相關文章