緩存設計:做好緩存設計的關鍵是什么?
緩存乃是一個用于臨時存儲數據的所在。當用戶進行數據查詢時,第一步便是在緩存中探尋,倘若找到了,便直接加以運用;要是未找到,就需前往數據的初始位置尋覓。因而,緩存實質上屬于一種以空間換取時間的技術手段,借由數據在空間層面的重復,來加快數據的訪問速度。
不過,伴隨分布式以及云計算技術的不斷發展,數據存儲技術已然發生了天翻地覆般的變化。而且,不同的存儲技術在價格和性能方面均存在極大的差異。所以,在針對性能展開軟件設計的時候,如果我們未能做好多層級的緩存設計,不但有可能造成金錢的浪費,而且所獲取的性能收益或許也難以達到理想狀態。
緩存設計的通關之路
那么首先,我打算從兩個問題入手,引領您了解緩存設計應在何時開展,以及通過對不同數據類型特性的對比分析,和您共同探討怎樣才能做好緩存設計。
好,第一個問題:在互聯網應用服務中,運用緩存技術的目的難道僅僅是為了提升訪問速度嗎?實際上,我覺得并非所有的緩存都只是為了提速,因為在分布式系統里,緩存機制實則是系統級性能設計的一項重要權衡手段。例如,當某個數據庫的負載較高,接近系統瓶頸時,我們能夠運用緩存技術,將負荷分攤至其他數據庫中,在此,使用緩存的目的,主要是實現負載均衡,而非提升訪問速度。
第二個問題:一個大型系統中的數據種類繁多,那么是否需要為每種數據都規劃緩存機制呢?其實完全沒必要。在實際的業務場景中,系統所包含的業務數據極多,您不可能針對每種數據都去設計和實現緩存機制,一方面是投入的軟件成本過高,另一方面也很可能無法帶來較高的性能收益。所以,在開展緩存設計之前,您首先需要辨別出哪些數據訪問對性能的影響較大。那么我們應當如何去辨別哪些數據需要緩存機制呢?
不過接下來,在識別出需要運用緩存機制的數據之后,您或許會發現,這些數據種類之間的特性差異極大,如果采用同一種緩存設計,實際上很難讓軟件性能達到最佳狀態。所以在此,我為您總結了三種需要緩存機制的數據種類,分別是不變性數據、弱一致性數據、強一致性數據。了解這三種緩存數據種類的差異,以及對應的設計緩存機制的方法,您就掌握了緩存設計的核心要義。
好,下面我們就來具體了解下吧。
首先是不變性數據。不變性數據意味著數據永遠不會發生變化,或者在相當長的一段時間內不會發生變化,所以我們也能夠認定這部分數據是不變的。此類數據屬于可以優先考慮運用緩存技術的一種數據類型,在實際的業務場景中數量眾多。例如,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(集合),作為緩存查詢分析,以此來優化性能。所以,您在進行緩存設計時,關注點應當置于不同的數據種類,以及不同層級緩存的性能評估模型上,而非僅僅關注數據庫。只有如此,您才能夠設計出更出色、更優良的性能緩存方案。