阿里架構師詳解緩存架構:如何減小沒必要要的計算?

本文已收錄GitHub,更有互聯網大廠面試真題,面試攻略,高效學習資料等git

互聯網應用的主要挑戰就是在高併發狀況下,大量的用戶請求到達應用系統服務器,形成了巨大的計算壓力。互聯網應用的核心解決思路就是採用分佈式架構,提供更多的服務器,從而提供更多的計算資源,以應對高併發帶來的計算壓力及資源消耗。github

那麼有沒有辦法減小到達服務器的併發請求壓力呢?或者請求到達服務器後,有沒有辦法減小沒必要要的計算,下降服務器的計算資源消耗,儘快返回計算結果給用戶呢?面試

有,解決的核心就是緩存。算法

所謂緩存,就是將須要屢次讀取的數據暫存起來,這樣在後面,應用程序須要屢次讀取的時候,就沒必要從數據源重複加載數據了,這樣就能夠下降數據源的計算負載壓力,提升數據響應速度。數據庫

通常說來,緩存能夠分紅兩種,通讀緩存和旁路緩存。瀏覽器

通讀(read-through)緩存,應用程序訪問通讀緩存獲取數據的時候,若是通讀緩存有應用程序須要的數據,那麼就返回這個數據;若是沒有,那麼通讀緩存就本身負責訪問數據源,從數據源獲取數據返回給應用程序,並將這個數據緩存在本身的緩存中。這樣,下次應用程序須要數據的時候,就能夠經過通讀緩存直接得到數據了。緩存

通讀緩存在架構中的位置與做用以下圖:服務器

阿里架構師詳解緩存架構:如何減小沒必要要的計算?

旁路(cache-aside)緩存,應用程序訪問旁路緩存獲取數據的時候,若是旁路緩存中有應用程序須要的數據,那麼就返回這個數據;若是沒有,就返回空(null)。應用程序須要本身從數據源讀取數據,而後將這個數據寫入到旁路緩存中。這樣,下次應用程序須要數據的時候,就能夠經過旁路緩存直接得到數據了。網絡

旁路緩存在架構中位置與做用以下圖:數據結構

阿里架構師詳解緩存架構:如何減小沒必要要的計算?

通讀緩存

互聯網應用中主要使用的通讀緩存是 CDN 和反向代理緩存。

CDN(Content Delivery Network)即內容分發網絡。咱們上網的時候,App 或者瀏覽器想要鏈接到互聯網應用的服務器,須要網絡服務商,好比移動、電信這樣的服務商爲咱們提供網絡服務,創建網絡鏈接才能夠上網。

而這些服務商須要在全國範圍內部署骨幹網絡、交換機機房才能完成網絡鏈接服務,這些交換機機房可能會離用戶很是近,那麼互聯網應用能不能在這些交換機機房中部署緩存緩存服務器呢?這樣,用戶就能夠近距離得到本身須要的數據,既提升了響應速度,又節約了網絡帶寬和服務器資源。

固然能夠。這個部署在網絡服務商機房中的緩存就是 CDN,由於距離用戶很是近,又被稱做網絡鏈接的第一跳。目前不少互聯網應用大約 80% 以上的網絡流量都是經過 CDN 返回的。

阿里架構師詳解緩存架構:如何減小沒必要要的計算?

CDN 只能緩存靜態數據內容,好比圖片、CSS、JS、HTML 等內容。而動態的內容,好比訂單查詢、商品搜索結果等必需要應用服務器進行計算處理後才能得到。所以,互聯網應用的靜態內容和動態內容須要進行分離,靜態內容和動態內容部署在不一樣的服務器集羣上,使用不一樣的二級域名,即所謂的動靜分離,一方面便於運維管理,另外一方面也便於 CDN 進行緩存,使 CDN 只緩存靜態內容。

反向代理緩存也是一種通讀緩存。咱們上網的時候,有時候須要經過代理上網,這個代理是代理咱們的客戶端上網設備。而反向代理則代理服務器,是應用程序服務器的門戶,全部的網絡請求都須要經過反向代理才能到達應用程序服務器。既然全部的請求都須要經過反向代理才能到達應用服務器,那麼在這裏加一個緩存,儘快將數據返回給用戶,而不是發送給應用服務器,這就是反向代理緩存。

阿里架構師詳解緩存架構:如何減小沒必要要的計算?

用戶請求到達反向代理緩存服務器,反向代理檢查本地是否有須要的數據,若是有就直接返回,若是沒有,就請求應用服務器,獲得須要的數據後緩存在本地,而後返回給用戶。

旁路緩存

CDN 和反向代理緩存一般會做爲系統架構的一部分,不少時候對應用程序是透明的。而應用程序在代碼中主要使用的是對象緩存,對象緩存是一種旁路緩存

不論是通讀緩存仍是旁路緩存,緩存一般都是以 <key, value> 的方式存儲在緩存中,好比,CDN 和反向代理緩存中,每一個 URL 是一個 key,那麼 URL 對應的文件內容就是value。而對象緩存中,key 一般是一個 ID,好比用戶 ID,商品 ID 等等,而 value 則是一個對象,就是 ID 對應的用戶對象或者商品對象。

對於 <key, value> 的數據格式,咱們在前面在數據結構討論過,比較快速的存取方式是使用 Hash 表。所以通讀緩存和旁路緩存在實現上,基本上用的是 Hash 表

程序中使用的對象緩存,能夠分紅兩種。一種是本地緩存,緩存和應用程序在同一個進程中啓動,使用程序的堆空間存放緩存數據。本地緩存的響應速度快,可是緩存可使用的內存空間相對比較小,可是對於大型互聯網應用所須要緩存的數據通以 T 計,這時候就要使用遠程的分佈式緩存了。

分佈式緩存是指將一組服務器構成一個緩存集羣,共同對外提供緩存服務,那麼應用程序在每次讀寫緩存的時候,如何知道要訪問緩存集羣中的哪臺服務器呢?咱們以 Memcached爲例,看看分佈式緩存的架構:

阿里架構師詳解緩存架構:如何減小沒必要要的計算?

Memcached 將多臺服務器構成一個緩存集羣,緩存數據存儲在每臺服務器的內存中。事實上,使用緩存的應用程序服務器一般也是以集羣方式部署的,每一個程序須要依賴一個Memcached 的客戶端 SDK,經過 SDK 的 API 訪問 Memcached 的服務器。

應用程序調用 API,API 調用 SDK 的路由算法,路由算法根據緩存的 key 值,計算這個key 應該訪問哪臺 Memcached 服務器,計算獲得服務器的 IP 地址和端口號後,API 再調用 SDK 的通訊模塊,將 <key, value> 值以及緩存操做命令發送給具體的某臺Memcached 服務器,由這臺服務器完成緩存操做。

那麼,路由算法又是如何計算獲得 Memcached 的服務器 IP 端口呢?比較簡單的一種方法,和 Hash 算法同樣,利用 key 的 Hash 值對服務器列表長度取模,根據餘數就能夠肯定服務器列表的下標,進而獲得服務器的 IP 和端口。

緩存注意事項

使用緩存能夠減小沒必要要的計算,可以帶來三個方面的好處:

  1. 緩存的數據一般存儲在內存中,距離使用數據的應用也更近一點,所以相比從硬盤上獲取,或者從遠程網絡上獲取,它獲取數據的速度更快一點,響應時間更快,性能表現更好。
  2. 緩存的數據一般是計算結果數據,好比對象緩存中,一般存放通過計算加工的結果對象,若是緩存不命中,那麼就須要從數據庫中獲取原始數據,而後進行計算加工才能獲得結果對象,所以使用緩存能夠減小 CPU 的計算消耗,節省計算資源,一樣也加快了處理的速度。
  3. 經過對象緩存獲取數據,能夠下降數據庫的負載壓力;經過 CDN、反向代理等通讀緩存獲取數據,能夠下降服務器的負載壓力。這些被釋放出來的計算資源,能夠提供給其餘更有須要的計算場景,好比寫數據的場景,間接提升整個系統的處理能力。

可是緩存也不是萬能的,若是不恰當地使用緩存,也可能會帶來問題。

首先就是數據髒讀的問題,緩存的數據來自數據源,若是數據源中的數據被修改了,那麼緩存中的數據就變成髒數據了。

主要解決辦法有兩個,一個是過時失效,每次寫入緩存中的數據都標記其失效時間,在讀取緩存的時候,檢查數據是否已通過期失效,若是失效,就從新從數據源獲取數據。緩存失效依然可能會在未失效時間內讀到髒數據,可是通常的應用均可以容忍較短期的數據不一致,好比淘寶賣家更新了商品信息,那麼幾分鐘數據沒有更新到緩存,買家看到的仍是舊數據,這種狀況一般是能夠接受的,這時候,就能夠設置緩存失效時間爲幾分鐘。

另外一個辦法就是失效通知,應用程序更新數據源的數據,同時發送通知,將該數據從緩存中清除。失效通知看起來數據更新更加及時,可是實踐中,更多使用的仍是過時失效。

此外,並非全部數據使用緩存都有意義。在互聯網應用中,大多數數據訪問都是有熱點的,好比熱門微博會被更多閱讀,熱門商品會被更多瀏覽。那麼將這些熱門的數據保存在緩存中是有意義的,由於緩存一般使用內存,存儲空間比較有限,只能存儲有限的數據,熱門數據存儲在緩存中,能夠被更屢次地讀取,緩存效率也比較高。

相反,若是緩存的數據沒有熱點,寫入緩存的數據很難被重複讀取,那麼使用緩存就不是頗有必要了

總結

緩存是優化軟件性能的殺手鐗,任何須要查詢數據、請求數據的場合均可以考慮使用緩存。緩存幾乎是無處不在的,程序代碼中可使用緩存,網絡架構中可使用緩存,CPU、操做系統、虛擬機也大量使用緩存,事實上,緩存最先就是在 CPU 中使用的。對於一個典型的互聯網應用而言,使用緩存能夠解決絕大部分的性能問題,若是須要優化軟件性能,那麼能夠優先考慮哪裏可使用緩存改善性能。

除了本文提到的系統架構緩存外,客戶端也可使用緩存,在 App 或者瀏覽器中緩存數據,甚至都不須要消耗網絡帶寬資源,也不會消耗 CDN、反向代理的內存資源,更不會消耗服務器的計算資源。

相關文章
相關標籤/搜索