1、正確的緩存設置順序:
一、讀:先從DB讀取以後,再寫到cache中
二、更新:先更新 DB 中的數據,再刪除 cache (必須是刪除,而不是更新cache)
錯誤操做1,更新DB,同時寫入cache
eg:進程A寫了cache,此時進程B打斷了A,又寫cache,並寫了DB,再次輪到進程A繼續寫DB,此時會致使,cache中保存的是B寫入的數據,而DB中保存了A寫入的數據,最終數據不一致,並且這個cache一直都是髒數據,若是此時不斷有進程來讀取,都是存在的cache髒數據;同理,若是先寫DB,在寫cache,同樣存在可能被打斷,最終致使cache是髒數據的問題
錯誤操做2,先刪除cache,再更新DB,高併發時可能出現的問題:
eg:進程A先刪除了cache,此時進程B打斷A,則從DB中讀取舊數據,並設置到了cache,再回來進程A更新DB,那麼從這裏開始,接下去全部的讀請求,都是舊cache,髒數據
2、緩存「擊穿」處理:
一個設置了過時時間的cache,在它過時那一刻,大量的併發請求會直連DB,DB負載太重問題。
解決辦法:
一、當獲取數據發現爲空時,說明cache過時了,此時不立刻鏈接DB,而是相似redis中的SETNX語法,設置一個tempkey=1,若是這個tempkey存在,則設置失敗,不存在則設置成功, 設置成功,則進行DB讀取數據,寫入cache,不然延時30s,再次重試讀cache,可能就有數據了。爲何這麼作?由於多進程併發的時候,第一個發現cache失效了,設置了tempkey,進行DB讀數據,其餘進程則由於沒法設置tempkey而等待一會,再讀數據。
1 def get_data(key=None):
2
3 value = redis.get(key)
4 if not value:
5 #緩存失效
6 if 1==redis.setnx(key+'tempkey', 1, 60): #設置一個臨時key,若是被其餘進程設置過了,則設置失敗,也就不會鏈接db
7 value = db.query('select name from test')
8 redis.set(key, value)
9 redis.delete(key+'tempkey')
10
11 else:
12 time.sleep(10)
13 get_data(key) #遞歸重試,或許已經能夠直接從cache中獲取了
14 else:
15 return value