先分享下我基于MAP實現的一個本地緩存
本地緩存
優勢:
1,易用,只是比map多了個過期時間,有超時的概念
2,用軟引用,可防止對JVM的堆對象造成out memory
3, 相對集中緩存不需要進行網絡開銷,消除RPC
缺點:
1,用的是堆內存。會對JVM的垃圾回收造成影響
2,大小控制只能是通過KEY值的存儲數量控制,無法通過控制內存占用大小
3,缺少監控方面的設計
4,沒有緩存的移除,定期清除失效緩存
5,緩存穿透的問題,當緩存失效時間時,大量訪問到了緩存的傳統,壓到數據庫去了
對于3,4問題可以用google的guava
對于1,ehcache可以用JAVA的直接內存.
對于直接內存這部分不好實現,JAVA只提供了個ByteBuffer.allocateDirect(capacity)的方法去應用直接內存,也就意味著要存入直接內存必須先把整個對象序列號成byte再放入直接內存。
但這樣每次都需要序列號與反序列化的開銷,而且得全量加載的堆內存引起垃圾回收。ehcache有直接用native方法實現
踩過的坑:
緩存失效
當緩存出現失效, 瞬間大量訪問壓到了DB,造成DB的壓力
解決:
1,不用失效時間來觸發緩存的更新
1, 后臺定時刷新最新內容到本地緩存,不依靠失效時間來觸發。
2, 結合廣播通知模式(如 redis)+本地緩存更新進行更新緩存,而不是通過失效來觸發(目前系統主要就是這個模式,待加上案例分享)
當然,兩種進行結合效果更好,
WEB服務器不停監控redis的訪問,同時定時輪詢,覆蓋緩存中的內容
2,通過控制進入DB操作的線程數進行控制
如, 通過重入鎖的,tryLock的condition,condition,阻塞超時方法,通知等進行控制(待加上案例分享)
緩存穿透
當訪問不存在的KEY時,一直傳入到數據庫層面去,壓到DB,造成DB的壓
解決:
1, 添加計數器,如當一個KEY的次數達到了10次后, 在緩存總加入該KEY,進行null的返回
2, 是否符合KEY的規則 + Bloom Filter, 用redis的bitmap存數組,對已存在的值進行hash存入(如果是ID,直接存,不需要hash,準確率100%)。 如果訪問的有bit位置為0的,必定不存在
返回同一對象地址
本地緩存讀取后的修改,會相互影響的問題
解決:
如果需要修改,返回對象需要進行深度clone
歡迎關注我的公眾號,重現線上各種BUG, 一起來構建我們的知識體系
文章列表