概覽
緩存是一個有着更快的查詢速度的存儲技術,這里的更快是指比起從初始的數據源查詢(比如數據庫,以下都稱作數據庫)而言。我們經常會把頻繁請求的或是耗時計算的數據緩存起來,在程序收到請求這些數據的時候可以直接從緩存中查詢數據返回給客戶端來提高系統的吞吐量,現在我們來看看有哪些緩存模式可以考慮。
Cache-Aside
Cache-Aside
是最廣泛使用的緩存模式之一,如果能正確使用Cache-Aside
的話,能極大的提升應用性能,Cache-Aside
可用來讀或寫操作。
讀操作
我們先來看下讀操作的數據流:
- 1、程序接收數據查詢的請求
- 2、程序檢查要查詢的數據是否在緩存上
- 如果存在(cache hit),從緩存上查詢出來
- 如果不存在(cache miss),從數據庫中檢索數據並存入緩存中
- 3、程序返回要查詢的數據
在Spring中,可如下實現,當getRecordForSearch()
方法被調用的時候,如果緩存中存在對應key的數據,那就會自動的從緩存中獲取(此時方法體不會被執行),當緩存中不存在key對應數據的時候,會執行方法體從數據庫中查詢數據並設置到緩存中去。
@Cacheable("default", key="#search.keyword)
public Record getRecordForSearch(Search search)
更新操作
如果程序需要更新數據庫中的數據且該數據也在緩存上,此時緩存中的數據也需要做相應的處理。為了解決這個不同步的問題來確認數據的一致性和操作性能,有兩個方式可按需使用。
緩存失效
該情況下,當請求需要更新數據庫數據的時候,緩存中的值需要被刪除掉(刪除掉就表示舊值不可用了),當下次該key被再次查詢到就去數據庫中查出最新的數據,在Spring中可實現如下:
@CacheEvict("default", key="#search.keyword)
public Record updateRecordForSearch(Search search)
緩存更新
緩存數據也可以在數據庫更新的時候被更新,從而在一次操作中讓之后的查詢有更快的查詢體驗和更好的數據一致性,在Spring中可實現如下:
@CachePut("default", key="#search.keyword)
public Record updateRecordForSearch(Search search)
為了應對不用類型的數據需要,有以下緩存加載策略可被選擇:
- 使用時加載緩存:當需要使用緩存數據時,就從數據庫中把它查詢出來,第一次查詢之后,接下來的請求都能從緩存中查詢到數據。
- 預加載緩存:在項目啟動的時候,預加載類似“國家信息、貨幣信息、用戶信息,新聞信息”等不是經常變更的數據。
Read-Through
Read-Through
和Cache-Aside
很相似,不同點在於程序不需要再去管理從哪去讀數據(緩存還是數據庫)。相反它會直接從緩存中讀數據,該場景下是緩存去決定從哪查詢數據。當我們比較兩者的時候這是一個優勢因為它會讓程序代碼變得更簡潔。
Write-Through
Write-Through
下所有的寫操作都經過緩存,每次我們向緩存中寫數據的時候,緩存會把數據持久化到對應的數據庫中去,且這兩個操作都在一個事務中完成。因此,只有兩次都寫成功了才是最終寫成功了。這的確帶來了一些寫延遲但是它保證了數據一致性。
同時,因為程序只和緩存交互,編碼會變得更加簡單和整潔,當你需要在多處復用相同邏輯的時候這點變的格外明顯。
當使用Write-Through
的時候一般都配合使用Read-Through
。
Write-Through
適用情況有:
- 需要頻繁讀取相同數據
- 不能忍受數據丟失(相對
Write-Behind
而言)和數據不一致
Write-Through
的潛在使用例子是銀行系統。
Write-Behind
Write-Behind
和Write-Through
在“程序只和緩存交互且只能通過緩存寫數據”這一點上很相似。不同點在於Write-Through
會把數據立即寫入數據庫中,而Write-Behind
會在一段時間之后(或是被其他方式觸發)把數據一起寫入數據庫,這個異步寫操作是Write-Behind
的最大特點。
數據庫寫操作可以用不同的方式完成,其中一個方式就是收集所有的寫操作並在某一時間點(比如數據庫負載低的時候)批量寫入。另一種方式就是合並幾個寫操作成為一個小批次操作,接着緩存收集寫操作(比如5個)一起批量寫入。
異步寫操作極大的降低了請求延遲並減輕了數據庫的負擔。同時也放大了數據不一致的。比如有人此時直接從數據庫中查詢數據,但是更新的數據還未被寫入數據庫,此時查詢到的數據就不是最新的數據。
總結
真實的系統中需求都不太一樣,我們應該根據自己的需要來選擇一個或組合幾個模式來完成實現。