緩存中常見的一些問題

整理了一些緩存相關的問題

術語

  • 命中

根據百度百科的解釋,終端用戶訪問加速節點時,如果該節點有緩存住了要被訪問的數據時就叫做命中,如果沒有的話需要回原服務器取,就是沒有命中。取數據的過程與用戶訪問是同步進行的,所以即使是重新取的新數據,用戶也不會感覺到有延時。 命中率=命中數/(命中數+沒有命中數), 緩存命中率是判斷加速效果好壞的重要因素之一。簡單來說,就是先去讀取緩存,讀取到了就是命中了。

  • 過期

過期有兩種,一種是時間過期,一種是淘汰過期。

時間過期好說,就是時間到了,被消除了。

所謂淘汰過期,只是在某些緩存服務器中對緩存內容大小進行了限制,當緩存接近於設置大笑時,會根據緩存服務的緩存策略進行操作,例如redis含有的一些淘汰策略:

  • voltile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
  • volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
  • volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
  • allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
  • allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
  • no-enviction(驅逐):禁止驅逐數據

緩存失效

也叫做緩存雪崩。某些項目可能會在配置項中寫一個固定的緩存過期時間,在併發比較高的情況下,可能會同時產生一些一些緩存鍵,這些緩存的的過期時候由於都是直接調取配置項,所以過期時間基本一致,這樣就會導致在某一時間這些緩存同時失效,請求全部到DB,DB可能會壓力過重。

解決方法:在緩存的時候給過期時間加上一個隨機值,這樣就會大幅度的減少緩存在同一時間過期。

緩存一致性

當數據時效性要求很高時,並且存在讀與寫場景都存在的併發場景,如何保證緩存的正確性?在寫操作中,是先刪除緩存還是操作完再重新覆蓋緩存?如果在集羣中,又如何保證副本緩存的同步?關於緩存一致性,內容稍微有點多,將在後期中詳細敘述。

緩存併發

當某一個緩存失效,通常的操作順序都是先查找數據,再進行操作,然後更新DB與cache。但在高併發的情況下,一個緩存過期會導致多個進程同時查找DB,如果緩存更新,對某個key有大量的併發請求,此時請求獲得的結果可能是更新之前也可能是更新之後,從而會導致“一致性”的問題。

解決辦法:由於緩存併發問題一般發生在查詢期間,所以當緩存失效的時候,對key加鎖。其他請求判斷到請求鎖存在,就等待,直到重新緩存完畢並解鎖。

緩存擊穿

指查詢一個一定不存在的數據,由於緩存是不命中時被動寫的,並且出於容錯考慮,如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到存儲層去查詢,失去了緩存的意義。當在流量較大時,出現這樣的情況,一直請求DB,很容易導致服務掛掉。

解決辦法:無論是否查詢到結果,都寫入緩存,但是查詢結果不存在的時候,設置過期時間稍短一點。


筆者認爲,在緩存失效前重新寫入緩存能有效的避免一些緩存問題,具體怎麼在緩存失效前重新寫入,方法有很多種,這裏就不討論了。

以上內容同步更新到了訂閱號【後端與web安全】(backend_websecurity)中,歡迎關注,不定期更新內容。轉載請以鏈接方式註明出處。

get

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章