緩存技術總結

注:緩存思想很通用,但本文可能會比較偏後端Java開發人員。

概述

定義:

  • 狹義上的緩存,Cache,高速緩衝存儲器,一種特殊的存儲器子系統,其中複製有頻繁使用的數據以利於快速訪問。
  • 廣義上的緩存,凡是位於速度相差較大的兩種硬件/軟件之間的,用於協調兩者數據傳輸速度差異的結構,均可稱之爲 Cache。

緩存可以級聯使用,可緩解甚至解決性能問題,無處不在:操作系統磁盤緩存(減少磁盤機械操作)、PC電腦中的內存、CPU中的二級緩存、HTTP協議中的緩存控制、CDN加速、Web服務器緩存、瀏覽器緩存(減少對網站的訪問)、數據庫緩存(減少文件系統I/O)、應用程序緩存……

緩存適合的場景:熱數據,讀多寫少,一致性要求不高。

常見緩存

操作系統緩存

  1. 文件系統提供的Disk Cache:操作系統會把經常訪問到的文件內容放入到內存當中,由文件系統來管理;
  2. 當應用程序通過文件系統訪問磁盤文件的時候,操作系統從Disk Cache當中讀取文件內容,加速文件讀取速度;
  3. Disk Cache由操作系統來自動管理,一般不用人工干預,但應當保證物理內存充足,以便於操作系統可以使用盡量多的內存充當Disk Cache,加速文件讀取速度;
  4. 特殊的應用程序對文件系統Disk Cache有很高的要求,會繞開文件系統Disk Cache,直接訪問磁盤分區,自己實現Disk;
  5. Cache策略
    Oracle的raw device(裸設備) – 直接拋棄文件系統
    MySQL的InnoDB: innodb_flush_method = O_DIRECT

數據庫緩存

  1. 查詢緩存
    Query Cache,以SQL作爲key值緩存查詢結果集,一旦查詢涉及的表記錄被修改,緩存就會被自動刪除,設置合適的Query Cache會極大提高數據庫性能,Query Cache並非越大越好,過大的Qquery Cache會浪費內存。MySQL:query_cache_size= 128M
  2. Data Buffer
    data buffer是數據庫數據在內存中的容器,其命中率直接決定數據庫的性能,data buffer越大越好,多多益善。MySQL的InnoDB buffer:innodb_buffer_pool_size = 2G,MySQL建議buffer pool開大到服務器物理內存60-80%。

應用緩存

1、對象緩存
由O/R Mapping框架例如Hibernate提供,透明性訪問,細顆粒度緩存數據庫查詢結果,無需業務代碼顯式編程,是最省事的緩存策略
當軟件結構按照O/R Mapping框架的要求進行針對性設計,使用對象緩存將會極大降低Web系統對於數據庫的訪問請求
良好的設計數據庫結構和利用對象緩存,能夠提供極高的性能,對象緩存適合OLTP(聯機事務處理)應用

頁面緩存

作用:針對頁面的緩存技術不但可以減輕數據庫服務器壓力,還可以減輕應用服務器壓力,好的頁面緩存可以極大提高頁面渲染速度,頁面緩存的難點在於如何清理過期的緩存。
分類
動態頁面靜態化
利用模板技術將訪問過一次的動態頁面生成靜態html,同時修改頁面鏈接,下一次請求直接訪問靜態鏈接頁面
動態頁面靜態化技術的廣泛應用於互聯網CMS/新聞類Web應用,但也有BBS應用使用該技術,例如Discuz!
無法進行權限驗證,無法顯示個性化信息
可以使用AJAX請求彌補動態頁面靜態化的某些缺點
II、Servlet緩存
針對URL訪問返回的頁面結果進行緩存,適用於粗粒度的頁面緩存,例如新聞發佈
可以進行權限的檢查
OScache提供簡單的Servlet緩存(通過web.xml中的配置)
也可以自己編程實現Servlet緩存
III、頁面內部緩存
針對動態頁面的局部片斷內容進行緩存,適用於一些個性化但不經常更新的頁面(例如博客)
OSCache提供了簡單的頁面緩存
可以自行擴展JSP Tag實現頁面局部緩存

服務器緩存

  • 反向代理服務器緩存,如nginx;
  • 靜態站點Web服務器緩存,如squid/nginx;
  • 靜態資源內容分發服務器緩存,如CDN;
  • servlet服務器緩存,如Tomcat;

瀏覽器緩存

緩存分類

  1. 本地緩存和遠程緩存

本地緩存

也叫進程緩存,實現技術:

  • guava cache
  • ehcache
  • Caffeine

參考本地緩存及Guava Cache&Caffeine使用

遠程緩存

也叫分佈式緩存,實現技術:

  • redis
  • memcache

緩存問題

緩存顛簸

也叫緩存抖動,一般是由於緩存節點故障導致,一致性Hash算法。

緩存雪崩

產生原因:高併發請求,緩存在同一時間大量失效,查db進而打垮db。
解決方案:

  1. 過期時間加隨機值;
  2. 如果Redis是集羣部署,將熱點數據均勻分佈在不同的Redis庫中也能避免全部失效。
  3. 設置熱點數據永不過期

緩存擊穿

產生原因:超級熱點Key,扛着大量的請求,當Key在失效的瞬間,大併發直接落到數據庫上,發生Key值的緩存擊穿。和緩存雪崩的區別在於這裏針對某一key緩存,前者則是很多key。
解決方案:

  1. 設置熱點數據永不過期
  2. 加上互斥鎖:在根據key獲得的value值爲空時,先鎖上,再從數據庫加載,加載完畢,釋放鎖。若其他線程發現獲取鎖失敗,則睡眠50ms後重試。
  3. 布隆過濾器:BloomFilter能夠迅速判斷一個元素是否在一個集合中。

緩存穿透

產生原因:查詢緩存中必定不存在的數據,緩存查詢cache_miss,導致查詢走到db層,流量大可能導致db掛掉。
解決方案:

  1. 在接口層增加校驗:用戶鑑權,參數做校驗,不合法的校驗直接 return
  2. 布隆過濾器(Bloom Filter),利用高效的數據結構和算法快速判斷出這個 Key 是否在數據庫中存在,不存在則return
  3. 後臺定時任務job,讀數據庫,寫更新到緩存。這種方案比較容易理解,但會增加系統複雜度。比較適合那些key相對固定、cache粒度較大的業務,key比較分散的則不太適合,實現也比較複雜

總結

緩存穿透和緩存擊穿,很相似,都是緩存未命中。擊穿是剛好key失效,穿透是key不存在。

上面三種問題的通用解決方案:

  1. 直接緩存NULL值
  2. 限流、降級、熔斷
  3. 緩存預熱
  4. 分級緩存,多級緩存
  5. 緩存永遠不過期

其他

Buffer & Cache

非常容易混用的概念。
Buffer,緩衝,緩和衝擊
Cache,緩存/快取,加快取用的速度
硬盤的讀寫緩衝/緩存名稱是不一樣的,write-buffer和read-cache。
一般都是讀寫混用,CPU裏的L2和L3 Cache也都是讀寫兼用。當然也有讀buffer
拿cache做buffer用呢?只要能控制cache淘汰邏輯就沒有任何問題。
拿buffer做cache用呢?在很特殊的情況下,能確定訪問順序的時候,也是可以的,但是比較侷限

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