緩存在架構設計中佔有重要地位。緩存在提升性能中也扮演重要的角色。常見的有對資源的緩存,比如數據庫連接池、http連接池,還有對數據的緩存等。緩存的設計可複雜也可簡單,但是需要考慮的點卻很多。
緩存對象
設計緩存的時候一定要考慮的是,緩存的對象是什麼,緩存哪些對象。緩存對象一定是熱數據,也就是頻繁被訪問。把對象加載到內存是以犧牲內存為代價的,如果緩存的對象不經常訪問,那麼就是在浪費內存,並且不但不會提升性能,還會因為命中率低的原因降低性能。
緩存的大小
因為內存是有限的,所以緩存不能無限大,那麼就要決定緩存多少數據以保證內存不被撐爆。
緩存一致性
緩存一致性是必須要考慮的點。很多緩存設計都忘記了這一點,導致在使用緩存的時候經常返回過期數據。數據在更新的時候,緩存可以採用如下幾個策略:1.將緩存中的數據設置為無效或者刪除,再次查詢的時候重新去數據庫查詢並更新緩存;2.更新數據時,先更新緩存,再更新數據庫或者先更新緩存之後異步刷新到數據庫;3.直接更新數據庫,緩存定期去數據庫同步最新數據,這種方式需要容忍一定時間內的不一致。緩存刷新策略一定要明確。作者本人在工作中遇到過這種情況:更新數據的接口有兩個,其中一個更新緩存後更新數據庫,另一個直接去更新的數據庫,由於沒有同步機制,導致總是偶現數據不一致的情況,而且只能重啟來規避。
緩存在哪裡
對於緩存數據的存儲位置也是需要考慮的。如果是分佈式系統或者近期會重構成分佈式的系統,緩存需要集中存儲,比如使用redis做緩存。如果是單機系統,最簡單的方式就是緩存到內存中。緩存的存儲位置的訪問一定要快於數據的存儲位置,不然緩存就沒有意義了。
緩存流程
經典緩存問題
1.緩存穿透
緩存穿透是指客戶端訪問即不在緩存中的數據又不在數據庫中的數據。這種訪問過多會導致數據庫掛掉影響正常訪問。對於這種問題,可以在數據訪問前做校驗,過濾掉不存在的數據訪問,必須不合法的查詢字段或者使用布隆過濾器,篩選掉不存在的數據;也可以將不存在的數據在緩存中建立空值緩存。
2.緩存擊穿
緩存擊穿是指客戶端訪問不在緩存中但數據庫中存在的數據。如果對某個key的訪問量很大,這個時候緩存過期了,那麼就會有很多的訪問漏到數據庫層面去訪問數據。這個問題可以採用如下方法解決:熱點數據常駐緩存;訪問在緩存中沒有拿到數據,在需要去數據庫中訪問數據時加鎖處理,只漏過一個訪問去數據庫查詢數據,並將數據更新到緩存,其他訪問加鎖失敗,後續從緩存中取數據。
3.緩存雪崩
緩存雪崩是指大量的key過期,導致訪問落到數據庫上。這個問題的解決方法如下:1.每個緩存數據設置不同的緩存時間,避免大量的緩存同時過期;2.添加的節點預熱。在需要添加緩存節點的時候,先做緩存預熱,避免大量訪問未命中的情況;3.對於熱點數據的判斷採用延遲的策略。在訪問緩存中不存在的數據的時候,不直接將它設置成最熱數據,而是設置到緩存數據按熱度排序中間的位置,避免某一時刻大量訪問冷數據導致熱數據被剔除緩存的情況。
建議
不建議在架構設計的最初階段就採用緩存。首先,採用緩存容易掩蓋一些問題,比如業務邏輯導致的性能低下在由於緩存的存在在初期不容易暴露;再有就是在最初階段有的時候很難去判斷什麼是熱數據什麼是冷數據,需要緩存什麼;如果已經確定要在系統中引入緩存那麼一定要考慮好上面的幾點。
閱讀更多 java技術小碼農 的文章