快取設計:做好快取設計的關鍵是什麼?

快取乃是一個​​用來暫時儲存資料的所在。當用戶進行資料查詢時,第一步便是在快取中探尋,倘若找到了,便直接加以運用;要是未找到,就需前往資料的初始位置尋覓。因而,快取實質上屬於以空間換取時間的技術手段,藉由資料在空間層面的重複,來加速資料的存取速度。

不過,伴隨分散式以及雲端運算技術的不斷發展,資料儲存技術已然發生了天翻地覆般的變化。而且,不同的儲存技術在價格和效能方面均存在極大的差異。所以,在針對效能展開軟體設計的時候,如果我們未能做好多層的快取設計,不但有可能造成金錢的浪費,而且所獲取的效能效益或許也難以達到理想狀態。

緩存設計的通關之路

那麼首先,我打算從兩個問題入手,引領您了解快取設計應在何時開展,以及透過不同資料類型特性的比較分析,和您共同探討怎樣才能做好快取設計。

好,第一個問題:在網路應用服務中,運用快取技術的目的難道只是為了提升存取速度嗎?實際上,我覺得並非所有的快取都只是為了提速,因為在分散式系統裡,快取機制實際上是系統級效能設計的重要權衡。例如,當某個資料庫的負載較高,接近系統瓶頸時,我們能夠運用快取技術,將負載分攤至其他資料庫中,在此,使用快取的目的,主要是實現負載平衡,而非提升存取速度。

第二個問題:一個大型系統中的資料種類繁多,那麼是否需要為每種資料規劃快取機制呢?其實完全沒必要。在實際的業務場景中,系統所包含的業務資料極多,您不可能針對每種資料都去設計和實現快取機制,一方面是投入的軟體成本過高,另一方面也很可能無法帶來較高的性能收益。所以,在進行快取設計之前,您首先需要辨別出哪些資料存取對效能的影響較大。那我們該如何去辨別哪些資料需要快取機制呢?

不過接下來,在辨識出需要運用快取機制的資料之後,您或許會發現,這些資料種類之間的特性差異極大,如果採用同一種快取設計,其實很難讓軟體效能達到最佳狀態。所以在此,我為您總結了三種需要快取機制的資料種類,分別是不變性資料、弱一致性資料、強一致性資料。了解這三種快取資料種類的差異,以及對應的設計快取機制的方法,您就掌握了快取設計的核心要義。

好,下面我們就來具體了解下吧。

首先是不變性資料。不變性資料意味著資料永遠不會發生變化,或在相當長的一段時間內不會發生變化,所以我們也能夠認定這部分資料是不變的。此類資料屬於可優先考慮運用快取技術的一種資料類型,在實際的業務場景中數量眾多。例如,Web 服務裡的靜態網頁、靜態資源,或資料庫表中列資料與key 的對應關係、業務的啟動配置等等,這些都能夠被視為不變性資料。

而且,不變性資料也意味著實現分散式一致性會極為容易,我們能夠為這些資料任選資料儲存方式,也能夠任選儲存節點位置。故而,我們實作快取機制的方式能夠十分靈活,也會相對簡單。例如在Java 語言中,您可以直接使用記憶體Caffeine,或內建的結構體當作快取均可。

另外這裡需要您注意,當您針對不變性資料進行快取設計時,其中的快取失效機制可以採用永遠不失效,或基於時間的失效方式。而在採用基於時間的失效方式時,您還需要依據具體的業務需求,在快取容量和存取速度之間做好設計實作方面的權衡。

弱一致性數據

第二種是弱一致性資料。它表示數據經常會發生變化,然而業務對於數據的一致性要求並不高,也就是說,不同用戶在同一時間點看到並非完全一致的數據,都是能夠被接受的。鑑於這類資料對一致性的要求相對較低,所以在設計快取機制時,您只需達成最終一致性即可。這類數據在實際業務裡也較為常見,例如業務的歷史分析數據、一些搜尋查找返回的數據等,即便最近的部分數據未被記錄進去,影響也不大。

另外,快速辨別這類數據還有一個辦法,那便是使用從資料庫Replica(複製)節點中讀取的數據,其中大部分都屬於這種類型的數據(很多數據庫Replica 節點的數據由於數據同步存在時延,是不滿足強一致性要求的)。針對弱一致性的數據,我們通常採用的快取失效機制是基於時間的失效方式,同時由於弱一致性的特點,您能夠較為靈活地選擇資料儲存技術,例如記憶體Cache,或是分散式資料庫 Cache。您甚至能夠基於負載平衡的調度,來設計多層級快取機制。

強一致性數據

第三種快取資料類型是強一致性資料。其指的是資料會頻繁發生變化,且業務對資料庫的一致性要求極高,也就是說當資料產生變更後,其他使用者在系統內的任何地方,都應當看到的是更新後的資料。

那麼,對於這種類型的數據,我通常不建議您使用快取機制,因為這類數據運用快取會較為複雜,並且極易引入新的問題。例如,使用者能夠直接提交和修改的各類數據內容,如果未同步修改快取中的數據,就會引發數據不一致性的問題,導致較嚴重的業務故障。

不過在某些特殊的業務場景中,例如,在個別資料存取頻率極高的情況下,我們依舊需要透過設計快取機制,來進一步提升效能。

因此針對這類強一致性數據,在設計快取機制時,您需要特別留意兩點:

這種資料的快取必須採用修改同步的實作方式。也就是說,所有的資料修改都必須確保能夠同步修改快取與資料庫中的資料。

精確識別特定業務流程中,能夠使用快取取得資料的時長。因為有些快取資料(例如一次REST 要求中,多個流程都需要使用的資料)只能夠在單次業務流程中使用,不能跨業務流程使用。

好了,以上便是三種典型的資料種類的快取設計思路了。

這裡您需要注意的是,使用快取必定是以效能最佳化為目的,因此,您還需要運用評估模型來分析快取是否達成了效能最佳化的目標。

那麼具體是何種評估模型呢?讓我們來看看這個效能評估模型的公式:AMAT = Thit + MR * MP。其中:AMAT(Average Memory Access Time),代表的是平均記憶體存取時間;Thit,指的是命中快取之後的資料存取時間;MR,是存取快取的失效率;MP,是指快取失效後,系統訪問快取的時間與存取原始資料請求的時間總和。

另外這裡您可能會留意到,AMAT 與原始資料存取之間的差值,代表的就是使用快取所帶來的存取速度的提升。而在一些快取使用不當的場景下,增加的快取機制很可能會造成資料存取速度下降的情況。所以接下來,我就透過真實的快取設計案例,來引領您理解如何正確地使用緩存,以此助力您更有效地提升系統效能。

快取設計的典型使用場景

好,在開始介紹之前呢,我還想為您說明一下,在真實的業務裡,快取設計的場景實際上有很多,在這裡我的目的主要是讓您明晰緩存設計的方法。

因此,我會從兩個較為典型的案例場景著手,引領您瞭解快取的運用。

如何做好靜態頁面的快取設計?

在Web 應用程式服務中,一個重要的應用程式場景便是靜態頁面的快取使用。這裡所說的靜態頁面,指的是在一個網站內,所有使用者看到的都是相同的頁面,除非重新部署,否則通常不會發生變更,例如大部分公司官網的首頁封面等等。通常情況下,靜態頁面的存取並發量是比較大的,如果您不運用快取技術,不但會導致使用者回應時延較長,而且會對後端服務造成極大的負載壓力。

那麼針對靜態頁面,我們在使用快取技術時,可以透過將靜態快取放置在距離使用者較近的位置,來降低頁面資料在網路上的傳輸延遲。

現在,我們來看一個針對靜態頁面使用快取設計的示意圖:

圖片圖片

如圖上所示,針對靜態網頁,首先您就能夠在軟體後端服務的實例中運用快取技術,以此避免每次都要重新產生頁面資訊。然後,由於靜態網頁屬於不變性數據,因此您可以使用記憶體或檔案層級快取。

另外,針對訪問量極大的靜態頁面,為了更進一步減輕對後端服務的壓力,您還能夠將靜態頁面置於網關處,接著利用 OpenResty 等第三方框架增添快取機制,以保存靜態頁面。

除此之外,在網頁中眾多的靜態頁面或靜態資源文件,還需要使用瀏覽器的緩存,來進一步提高效能。請注意,這裡我並非建議您針對所有的靜態頁面,都需要設計三層的快取機制,而是您要知曉,在軟體設計階段,通常就需要考慮如何進行靜態頁面的快取設計了

後端服務如何設計資料庫的多層快取機制?

還有一個典型的快取場景是針對資料庫的快取。現在的資料庫通常都是分散式儲存的,而且規模都比較大,在針對大規模資料進行查詢與分析計算時,都需要花費一定的時間週期。因此,我們可以先識別出這些計算結果中可以使用快取機制的數據,然後就可以使用快取來提升存取速度了。下面是一張針對資料庫快取機制的原理圖:

圖片圖片

從圖上能夠看到,記憶體級Cache、分散式Cache 均可作為資料運算分析結果的快取。而且,不同級別的快取存​​取速度存在差異,記憶體級的Cache 存取速度能夠達到微秒級別,甚至更優;分散式Cache 存取速度通常小於毫秒級別;而對於原生資料庫的查詢與分析,通常大於毫秒級別。

因此,在具體規劃快取機制的時候,您就需要依照前面我所介紹的快取使用原理,辨別出資料類型,進而選擇並設計快取實作機制。

另外,在透過快​​取機制實現存取速度最佳化的過程中,我們主要關注的是不同層級快取所帶來的存取速度提升,並且在此處,不同層級快取也能夠存在於一個資料庫中。

例如,在我參與設計的一個效能最佳化專案裡,其Cache 策略便是,使用MongoDB 中的另外一個Collection(集合),作為快取查詢分析,以此來最佳化效能。所以,您在進行快取設計時,關注點應置於不同的資料種類,以及不同層級快取的效能評估模型上,而非只專注於資料庫。只有如此,您才能夠設計出更出色、更優良的效能快取方案。