一般應用而言,追求的都是快取的最終一致性。
一般的快取系統,都是按照key去快取查詢,如果不存在對應的value,就應該去後端系統查詢(比如db)。如果key對應的value是一定不存在的,並且對該key併發請求量很大,就會對後端系統造成很大的壓力。這就叫做快取穿透。
引起這個問題的主要原因還是高併發的時候,平時我們設定乙個快取的過期時間時,可能有一些會設定1分鐘啊,5分鐘這些,併發很高時可能會出在某乙個時間同時生成了很多的快取,並且過期時間都一樣,這個時候就可能引發一當過期時間到後,這些快取同時失效,請求全部**到db,db可能會壓力過重。
那如何解決這些問題呢?
其中的乙個簡單方案就時講快取失效時間分散開,比如我們可以在原有的失效時間基礎上增加乙個隨機值,比如1-5分鐘隨機,這樣每乙個快取的過期時間的重複率就會降低,就很難引發集體失效的事件。
下面的幾種方案中,都要設定快取過期時間。以避免一旦出現髒資料後產生無法保證最終一致性。
明顯是錯誤的。兩個併發操作,乙個是更新操作,另乙個是查詢操作,更新操作刪除快取後,查詢操作沒有命中快取,先把老資料讀出來後放到快取中,然後更新操作更新了資料庫。於是,在快取中的資料還是老的資料,導致快取中的資料是髒的,而且還一直這樣髒下去了。
但是這種方法是在是簡單到讓人喜歡,所以,有人將其利用佇列完全改造了成了串形模式,當出現更新請求時,先扔進佇列,然後非同步依次執行即可。
先把資料存到資料庫中,成功後,再讓快取失效。
這是最常用的套路。
乙個是讀操作,但是沒有命中快取,然後就到資料庫中取資料,此時來了乙個寫操作,寫完資料庫後,讓快取失效,然後,之前的那個讀操作再把老的資料放進去,所以,會造成髒資料。但是實際上出現的概率可能非常低,因為這個條件需要發生在讀快取時快取失效,而且併發著有乙個寫操作。而實際上資料庫的寫操作會比讀操作慢得多,而且還要鎖表,而讀操作必需在寫操作前進入資料庫操作,而又要晚於寫操作更新快取,所有的這些條件都具備的概率基本並不大。
我們可以再讓快取失效後立刻模擬一次呼叫來重新整理快取。
由於快取長期不一致會引起客戶投訴。所以我們可以採取更高水平的快取保證。
/** * 更新方法,更新資料庫後再使對應條目的cache條目失效
* @param o 需要更新的資料,pojo形式
* @param key 該條目存在cache中的key
* @return 是否成功
*/public
boolean
put(object o, object key)
catch
(exception e)
finally
return ret;
}/**
* 刪除方法,刪除資料庫後再使對應條目的cache條目失效
* @param key 資料存在於cache中的key,也用於該條資料查詢資料庫的條件(i.e. id)
* @return 是否成功
*/public
boolean
del(object key)
catch
(exception e)
finally
return ret;}(
)}
快取一致性
計算機體系結構量化研究方法 第五版 學習筆記 快取一致性 1 快取一致性的問題 2 儲存器一致性的概念 3 一致性的基本實現方案 大型 多級快取可以充分降低處理器對儲存頻寬的需求。採用對稱共享儲存器的計算機通常支援對共享資料與專用資料的快取。多處理器之間的通訊基本上是通過讀寫共享資料實現。為了降低訪...
快取一致性協議
作業系統的cpu和記憶體並不是直接互動操作的。我們的cpu有一級快取,cpu直接操作一級快取,由一級快取和記憶體進行互動。所以同乙個程式,cpu進行切換的時候,切換前和切換後的資料可能會有不一致的情況。那麼這個就是乙個很大的問題了。如何保證各個cpu快取中的資料是一致的。就是cpu的快取一致性問題。...
Redis快取一致性
用過redis的應該都清楚,redis作為記憶體快取,只是他查詢快的一大優勢,關係型資料庫只能用作儲存重要資料,或者備份快取的資料,這個時候,不可避免,我們會遇到快取中的資料與關係型資料庫中的資料不一致的情況。出現不一致的現象很常見,如果你是單個使用者肯定不會出現這種情況,如果在多執行緒併發的情況下...