直接硬核干貨,去掉前戲。
方案大致說明
1:假設對redis中存在一對key,value的對應關系是 key=money,value=666
2:當修改線程修改key時先將key設置成value=666_write,(這里需要說明的是:線上實際應用可以將_wirte改成非常復雜的UUID等字符串,只要保證不要和線上實際set的值沖突即可,例如666_write_@#$%^&*_qwerty
3:當讀取時發現key的存在讀取標識666_read_@#$%^&*_qwerty,發現有其他讀取線程已經在從DB中load數據了,這種情況休眠一下重試就可以了,不需要從DB中load數據,因為這樣做會引起大量線程訪問數據庫引發災難。如果不存在讀取標識則判斷一下是否含有寫入標識若不存在則直接返回數據即可,若存在讀取標識將所有讀取標識去掉之后看看是否為空,不為空則返回當前value即可。
4:為什么一個字符串會出現多個寫入標識呢。假設線程A和B對 key=money,value=666的數據進行修改,那么線程A將value變成了value=666_write_@#$%^&*_qwerty,這個時候線程B也來摻和一下,會變成666_write_@#$%^&*_qwerty_write_@#$%^&*_qwerty,這個地方是需要注意的。同時也會出現業務數據被刪除了這個時候加上了修改標記,value變成_write_@#$%^&*_qwerty這種只有修改標識但是沒有業務數據的的情況。
5:還有一個需要特別注意的是setnx在客戶端2.8之后 支持超時時間,這塊需要設置一個超時的時間處理,防止讀取線程setnx之后服務器掛了,引起永遠無法同步的問題,至於超時時間設置成多少和實際環境有關。
6:同時也會出現_read_@#$%^&*_qwerty_write_@#$%^&*_qwerty這種同時帶有read和write的情況,出現在並發讀取的場景。
7:這種需要DB緩存強一致讀寫應該在master中進行,不應該在slave中讀,很有可能出現延遲導致問題
8:redis主從切換這種極端的場景出現在讀取或者修改的情況下也會引起數據不一致的問題,一般上線這種問題的解決方案是跨機房多機緩存或者允許短期內不一致的job任務定時校驗兜底等。
總結起來就是一下幾點:
當存在_read_@#$%^&*_qwerty時說明有讀取線程正請求DB,從新load對象。
當存在_write_@#$%^&*_qwerty時說明當前key正在被寫入。
當存在多個_write_@#$%^&*_qwerty時 存在並發修改。
當有_read_@#$%^&*_qwerty和_write_@#$%^&*_qwerty時 存在讀和寫的並發。
讀取詳細設計方案
更新時設計方案:
其他問題加群討論吧 QQ群號:825199617。