1. 程式人生 > >架構真經 | 那些年,我們踩過的快取坑

架構真經 | 那些年,我們踩過的快取坑

  在碼農的世界裡,一直以來都有一個信仰:只要使用了快取,效能就會翻倍;用上快取的應用就像是打通任督二脈的武林高手,內力生生不息。但是今天我想跟各位猿類朋友聊一聊自己在使用快取時遇到的那些坑,這裡主要講物件快取應用部分,想了解全面的推薦閱讀《架構真經》。

正文

案例一

前幾天突然發現 Redis 監控顯示某 Redis 例項記憶體使用量突破了 14G 大關,當時我就震驚了,這是要翻車的節奏啊!通過 info 指令檢視,發現 key 的量並不是太高,所以懷疑有個別業務 value 的 size 比較大,為了保證生產不受影響,從生產上匯出 rdb 檔案進行分析。通過

rdb -c memory redis_dump.
rdb —bytes 1024 -f memory.csv

將大於1024 位元組的 key 匯出。然後進行排序:

sort -t, -k4nr memory.csv |head -n 20

終於找到了罪魁禍首。如下圖:

1

緊急刪除該 key 臨時解決了問題,經覆盤發現,此問題是開發時快取使用不當,所有資訊都不過期,資料只能越增越大。

總結:快取中放置的應該是熱資料,同時快取策略也存在問題,應該針對每條記錄設定不同的 key ,而不是都放在一個 key 下。

案例二

某歷史專案最近總是報警(系統負載升高,響應變慢,應用頻繁 GC),只能頻繁重啟應用。分析 Dump 檔案,發現建立的物件非常多,但沒有明顯的佔用大戶。於是繼續分析佔用記憶體較大的物件,發現都是 Hibernate 的代理物件;接下來去看 Hibernate 的配置,發現開啟了二級快取,同時 Ehcache 中沒有控制快取物件的個數,導致應用啟動一段時間後,隨著快取物件的增多,很快會導致 GC 了。於是我們緊急上線,關閉了部分物件的快取,問題得到了初步緩解。

總結:當使用本地快取(如 Ehcache)時,一定要嚴格控制快取物件的個數及生命週期。由於 JVM 的特性,過多的快取物件會極大的影響 JVM 效能。

案例三

某個正常執行的應用突然報警執行緒數高,之後很快就記憶體溢位。檢視日誌發現無法連線 Memcached,繼而檢視 Memcached 配置,發現連線數過高,拒絕連線。而應用連線 Memcached 的超時時間較長,導致請求執行緒不斷堆積,最後應用記憶體溢位。臨時解決方案是先增加 Memcached 的連線數,之後應用修改連線超時時間。

總結:當我們在使用遠端快取(如 Redis、Memcached)時,一定要對超時時間進行控制,一般來講快取的總體響應時間不能高於 50ms ,否則快取會成為應用的負擔,而不是幫手。

案例四

某專案關鍵業務忽然報警業務波動,檢視應用日誌發現訪問 Redis 異常,檢視 Redis 發現做了主備切換;這次超時時間設定沒問題,但沒有針對快取不可用做降級處理,導致業務流程中斷。

總結:使用快取時,一定要有降級處理;尤其是關鍵業務環節。

案例五

某專案使用快取後,開發測試沒問題,上生產後,服務卻不可用。檢視日誌發現是該應用的快取 key 與其他應用快取的 key 衝突,導致錯誤。

總結:快取使用時,一定要有隔離的設計。比如 Redis 可以選擇不同的 DB,或者 Ehcache 定義不同的 Cache 名。如果這些都不方便實施,至少也要有 key 的命名規範,否則天知道會發生什麼。

案例六

某專案使用 Redis 快取臨時資料,上線後出現錯誤資料,但由於沒有開發管理功能,導致發生問題時,看不到資料,也無法管理,使得應急時間較長。

總結:當使用快取後,一定提供相應的管理手段。否則發生事故時,只能兩眼一抹黑。

案例七

某應用在訪問時經常時快時慢,同時 DB 負載也忽高忽低;分析程式碼發現專案中快取設定了一個固定的失效時間,當快取失效時,會造成一段時間內訪問 DB 的請求非常集中。

總結:簡單方案就是將快取失效時間分散開,比如我們可以將失效時間設定為一個區間內的隨機值,這樣每一個快取的過期時間的重複率就會降低,就很難引發集體失效的事件。

案例八

某計費專案發現計算結果有誤差,分析日誌時發現:系統修改規則後,較長時間仍在使用舊規則。檢視 Ehcache 配置檔案發現過期時間很長,導致規則更新後,很長時間不生效,部分訂單計算費用出現誤差。

總結:使用本地快取又需要資料一致性時,可以考慮用 Zookeeper 之類的協調服務,實現一個更高效的快取更新機制。

案例九

這是一個快取穿透的案例,某模組設計使用了快取,但發現數據庫負載並沒有大幅下降。分析程式碼發現,快取邏輯如下:資料庫存在紀錄則放到快取中,不存在則下次仍然會訪問資料庫;導致不存在的訂單頻繁查詢時,快取沒有效果。

總結:快取穿透是一個常見問題,我們需要把 null 也作為一種快取結果,否則此類情況等於快取是失效的。

結尾

  以上這些案例都是我們親身經歷的血的教訓,在研發過程也是很容易忽略的點。誠然使用快取是提高應用效能的有效手段,但沒有深入的分析與設計就很容易造成災難性的影響。我思故我在,我們猿類最大的優點就是思考能力,希望這些小案例能引起大家更深層次的思考。另外,軟體設計思想來源於生活,比如看看 CPU 的設計,有一級快取、二級快取,估計有很多小夥伴也在做快取設計時這樣做了。生活中處處有設計,只要用心總能觀察到。

《架構真經》:《架構即未來》姊妹篇,矽谷大咖的乾貨呈現,網際網路架構的 50 條軍規。唐彬、向江旭、葉亞明、段念、吳華鵬、張瑞海、韓軍、程炳皓、張雲泉、餘晨、李大學、霍泰穩聯袂力薦。京東 · 傳送門:架構真經:網際網路技術架構的設計原則(原書第2版)