日常編程中,對於一些有一定並發量或數據量較高的數據庫操作,我們都會在前端加一層緩存層,並設置失效時間,現在一般是mongoDB或memcached,簡單流程如下:
這個模式在並發量並非太高或數據操作效率很高的情況下基本沒有什麼問題。
但是也許你已經看到了,if(緩存失效 && 恰好遇到並發量很高 && 數據庫操作時間長) then?
1. 緩存失效
2. 第一個進程去數據庫獲取新數據,假如包括SQL+程序邏輯耗時5S
3. 這5S內,第二個、第三個...第N個都只是獲取到已失效的緩存,於是也都連接數據庫...
4. 結果顯而易見,數據庫鎖表 -> 數據庫累計大量進程 -> 直至數據庫掛掉!
那麼,如何去解決這個問題呢?其實最簡單的方案就是:
添加一個標記,類似文件鎖,用於判斷此時程序是否正在更新緩存。
若是,則直接返回舊緩存(標記有設置失效時間,避免由於程序錯誤導致標記未刪除而引起的緩存不更新問題)
若否,則設置一個標記,然後進行數據獲取及緩存更新,最後刪除標記。
PS. 第一次生成緩存的話可能會有些用戶無法看到數據,不過這個幾率很小,且可以通過其他方式如手動生成之類去解決。
流程如下: