聊聊緩存模式

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"引言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在系統設計中,爲了提高數據的處理速度緩存的使用無處不在。比如爲了彌補CPU處理速度和數據IO的差距,依次有寄存器、CPU緩存、內存、硬盤金字塔模式的不同存儲介質。而在上層的業務應用中,爲了提高請求處理速度,通常會增加一層緩存來存儲熱點數據。而對於緩存數據的處理方式有如下幾種模式。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"旁路緩存 Cache-Aside","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"旁路緩存模式是開發中最常使用的一種緩存模式,它的核心思路在於僅當一個對象被請求時纔將它加入緩存。該模式下緩存數據的讀寫流程如下:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c4/c45a96b7a5a86ed0636d79956743f406.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據讀取","attrs":{}}]}]}],"attrs":{}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"業務側發起數據查詢讀取請求","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"處理服務首先嚐試從緩存讀取加載數據","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"判斷緩存中數據是否存在,如果存在則直接返回緩存數據","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"否則,從數據庫等主存加載數據,並將數據寫入緩存","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"返回最終查詢結果","attrs":{}}]}]}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據更新","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 業務側發起數據寫入/更新請求","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 處理服務首先對數據庫等主存進行更新寫入操作","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 完成後將對應緩存數據刪除失效","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"模式分析","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"旁路緩存的設計模式主要適用於對數據的讀取頻率遠大於寫入更新頻率的場景下,即數據一旦寫入後數據不再變換或很少變化的情況,並通過採用LRU等數據淘汰策略,緩存熱點數據。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但該模式下數據的更新操作因爲需要處理數據和緩存,且不是原子操作,所以很容易出現數據不一致的情況。需要根據實際的業務對數據一致性的要求進行處理。具體可參考《一文搞定緩存和數據庫一致性》[鏈接]","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"通讀/通寫 Read-Through/Write-Through","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通讀通寫模式是將數據的緩存處理操作統一進行了封裝處理,增加一個緩存層,對應用屏蔽底層數據處理的細節。在旁路緩存模式中,應用需要自行處理緩存命中或未命中的處理邏輯,增加複雜度。而通過增加緩存層,業務服務僅和緩存打交道,不去關心具體數據的來源。數據讀寫流程如下:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/24/24dd894e16818846d2025d046906a224.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據讀取","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據讀取流程和旁路緩存類似,只是將緩存邏輯由緩存層統一處理。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據更新","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據更新時,由緩存層作爲一個事務同時更新主存和緩存數據。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"模式分析","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通讀/通寫模式適用於對相同數據頻繁讀寫的情況,並且對主存和緩存數據有強一致性要求的情況,例如銀行的業務系統。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"緩存回寫 Write-Behind","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存回寫和Write-Through類似,只是在Write-Though模式下會在處理請求時同時處理主存和緩存的數據,而回寫模式只對緩存的數據進行更新,然後採用異步的方式將緩存中的數據回寫到主存中。數據寫入更新流程如下:","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6f74a3a3d52371a2163d6d86e3a76aa7.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存數據的異步回寫可以採用多種方式,比如:按固定的時間頻率定時回寫,或者統計數據更新的次數(或固定大小)並在達到一定次數(大小)時進行回寫。還可以兩者結合:時間或者更新次數任何一個達到指定值則觸發回寫操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在MySQL中對於數據的更新操作即採用了類似的模式。MySQL將存儲的數據按照頁的方式讀取到內存中,當更新數據時只會更新內存中加載的數據,這時數據的緩存頁和磁盤中數據不一致,被更改的數據頁稱爲“髒頁”。在髒頁被淘汰、或者數據庫空閒、關閉等情況下,觸發對髒頁的數據回寫。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"模式分析","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存回寫的模式一方面因爲業務請求僅需要對換粗數據更新即可完成操作,極大的降低了數據寫入的時間,提高了處理效率;另一方面因爲緩存數據和主數據的不一致,會導致出現讀取到老數據的情況。另外由於寫入主存儲是有延時的,在異常情況下可能出現數據丟失。因此採用該模式需要能容忍一定的數據不一致,並且對可能的數據丟失可以接受或者補償。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"沒有任何一種模式是完美的,具體選擇哪一種緩存的策略需要結合實際的業務情況,並針對所選模式的劣勢或缺陷進行額外的補償處理。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外緩存的設計及其他很多設計模式,硬件層面和軟件層面會在解決某些問題時出現一樣的方案,所以瞭解和熟悉底層系統或硬件的優秀設計,對於上層應用和現在微服務情況下方案設計有很大的參考意義。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章