您好,登錄后才能下訂單哦!
在項目中緩存是經常用到的,為了減少和數據庫的交互,小伙伴們利用緩存的思路如下:
緩存設計思路
我們小伙伴們有沒有考慮到緩存更新的問題,小伙伴們肯定會說肯定用過啊,有數據更新時,把緩存清空掉就行了啊,下一次訪問的時候服務就會把新值設置到緩存中了。這樣不就行了嗎?對的,在一般項目中,這樣的使用就夠了。那老顧帶著大家看看在高并發場景下,會有什么問題?
我們舉例說明,就拿商品的庫存作為緩存。那現在我們要更新緩存中的庫存值,怎么進行操作,我們看下面幾個場景:
存在的問題場景:請求A更新值為99,請求B更新值為98
上圖流程:
這樣數據庫的值為98,但緩存的值為99,數值不一致。(不推薦)
這個流程跟上面很類似,出現的問題也很類似
這樣就緩存的值為98,數據庫為99導致不一致。(不推薦)
存在的問題場景:請求A更新值為99,請求B獲取值
上圖中請求流程:
這樣就導致了緩存和數據庫的不一致問題,緩存中的值一直是舊數據。(不推薦)
這個方案也是老外提出的《Cache-Aside pattern》更新緩存的策略。這種策略先保證了源頭的數據一定是正確的。這種策略是不是萬無一失呢,有一種非常特殊的場景
上圖流程:建立中緩存突然失效了
這種情況發生的不一致,是因為緩存突然失效了。而且還要保證請求B更新操作 比 請求A的查詢操作還要快;才會導致不一致。這種情況概率會很少。一般要求不高的項目可以采用此方式(推薦)。
這種先更新數據庫,再刪除緩存的策略中,因為要刪除緩存,但如果緩存刪除失敗,就會導致數據庫與緩存不一致。這個問題怎么辦?我們正常想到的是利用我們MQ中間件去實現。
上圖的流程,如果刪除緩存失敗,發送消息投遞到消息中間件中,進入消息隊列。也許有小伙伴就會問,如果消息投遞失敗怎么辦?我們可以利用消息中間件那邊的保證100%消息投遞的機制(這個以后再講)。這樣就保證了即使刪除消息失敗,我們也會重試。
不過這個方案有個問題,就是和我們應用服務的業務代碼耦合的比較厲害。代碼業務不清晰。
那我們有沒有別的方案呢,對業務沒有侵入呢?
上圖中其實是利用了mysql的底層機制,binlog日志進行刪除緩存,這樣就不需要和業務關聯,刪除緩存服務是獨立的。我們可以利用阿里開源的canal去操作。
這種先更新數據庫,再刪除緩存的策略是不是就沒有問題呢?我們來看一下另一個場景,數據庫的讀寫分離的場景。一般中大型項目都會用到數據庫的讀寫分離。寫請求在一個庫,讀請求在另一個庫。讀寫分離會有個問題,就是庫與庫之間會存在數據延遲,因為存在數據同步。
那我們再看一下上面的場景流程,就會有問題,因為請求B更新數據 在一個庫上面,請求A去讀取數據時是另一個庫。
這樣就導致不一致,這個場景是經常出現的,不是小概率事件。那我們如何處理呢?老顧下次再介紹。
總結:整個導致不一致的原因就是因為高并發情況下各個請求執行的順序是無法確定的,不知道哪個請求先執行,哪個后執行導致。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。