前言
大家好!我是萬俊峰,go-zero 作者。感謝 ArchSummit 提供這么好的機會來跟大家分享一下go-zero的緩存最佳實踐。
首先,大家可以想一想:我們在流量激增的情況下,服務端哪個部分最有可能會是第一個瓶頸?我相信大部分人遇到的都會是數據庫首先扛不住,量一起來,數據庫慢查詢,甚至卡死。此時,上層服務有怎么強的治理能力都是無濟於事的。
所以我們常說看一個系統架構設計的好不好,很多時候看看緩存設計的如何就知道了。我們曾經遇到過這樣的問題,在我加入之前,我們的服務是沒有緩存的,雖然當時流量還不算高,但是每天到流量高峰時間段,大家就會特別緊張,一周宕機好幾回,數據庫直接被打死,然后啥也干不了,只能重啟;我當時還是顧問,看了看系統設計,只能救急,就讓大家先加上了緩存,但是由於大家對緩存的認知不夠以及老系統的混亂,每個業務開發人員都會按照自己的方式來手撕緩存。這樣導致的問題就是緩存用了,但是數據七零八落,壓根沒有辦法保證數據的一致性。這確實是一個比較痛苦的經歷,應該能引起大家的共鳴和回憶。
然后我把整個系統推倒重新設計了,其中緩存部分的架構設計在其中作用非常明顯,於是有了今天的分享。
我主要分為以下幾個部分跟大家探討:
- 緩存系統常見問題
- 單行查詢的緩存與自動管理
- 多行查詢緩存機制
- 分布式緩存系統設計
- 緩存代碼自動化實踐
緩存系統涉及的問題和知識點是比較多的,我分為以下幾個方面來討論:
- 穩定性
- 正確性
- 可觀測性
- 規范落地和工具建設
由於篇幅太長,本文作為系列文章第一篇,主要跟大家探討『緩存系統穩定性』
緩存系統穩定性
緩存穩定性方面,網上基本所有的緩存相關文章和分享都會講到三個重點:
- 緩存穿透
- 緩存擊穿
- 緩存雪崩
為什么首先講緩存穩定性呢?大家可以回憶一下,我們何時會引入緩存?一般都是當DB有壓力,甚至經常被打掛的情況下才會引入緩存,所以我們首先就是為了解決穩定性的問題而引入緩存系統的。
緩存穿透
緩存穿透存在的原因是請求不存在的數據,從圖中我們可以看到對同一個數據的請求1會先去訪問緩存,但是因為數據不存在,所以緩存里肯定沒有,那么就落到DB去了,對同一個數據的請求2、請求3也同樣會透過緩存落到DB去,這樣當大量請求不存在的數據時DB壓力就會特別大,尤其是可能會惡意請求打垮(不懷好意的人發現一個數據不存在,然后就大量發起對這個不存在數據的請求)。
go-zero 的解決方法是:對於不存在的數據的請求我們也會在緩存里短暫(比如一分鍾)存放一個占位符,這樣對同一個不存在數據的DB請求數就會跟實際請求數解耦了,當然在業務側也可以在新增數據時刪除該占位符以確保新增數據可以立刻查詢到。
緩存擊穿
緩存擊穿的原因是熱點數據的過期,因為是熱點數據,所以一旦過期可能就會有大量對該熱點數據的請求同時過來,這時如果所有請求在緩存里都找不到數據,如果同時落到DB去的話,那么DB就會瞬間承受巨大的壓力,甚至直接卡死。
go-zero 的解決方法是:對於相同的數據我們可以借助於 core/syncx/SharedCalls
來確保同一時間只有一個請求落到DB,對同一個數據的其它請求等待第一個請求返回並共享結果或錯誤,根據不同的並發場景,我們可以選擇使用進程內的鎖(並發量不是非常高),或者分布式鎖(並發量很高)。如果不是特別需要,我們一般推薦進程內的鎖即可,畢竟引入分布式鎖會增加復雜度和成本,借鑒奧卡姆剃刀理論:如非必要,勿增實體。
我們來一起看一下上圖緩存擊穿防護流程,我們用不同顏色表示不同請求:
- 綠色請求首先到達,發現緩存里沒有數據,就去DB查詢
- 粉色請求到達,請求相同數據,發現已有請求在處理中,等待綠色請求返回,singleflight模式
- 綠色請求返回,粉色請求用綠色請求共享的結果返回
- 后續請求,比如藍色請求就可以直接從緩存里獲取數據了
緩存雪崩
緩存雪崩的原因是大量同時加載的緩存有相同的過期時間,在過期時間到達的時候出現短時間內大量緩存過期,這樣就會讓很多請求同時落到DB去,從而使DB壓力激增,甚至卡死。
比如疫情下在線教學場景,高中、初中、小學是分幾個時間段同時開課的,那么這時就會有大量數據同時加載,並且設置了相同的過期時間,在過期時間到達的時候就會對等出現一個一個的DB請求波峰,這樣的壓力波峰會傳遞到下一個周期,甚至出現疊加。
go-zero 的解決方法是:
- 使用分布式緩存,防止單點故障導致的緩存雪崩
- 在過期時間上加上5%的標准偏差,5%是假設檢驗里P值的經驗值(有興趣的讀者可以自行查閱)
我們做個實驗,如果用1萬個數據,過期時間設為1小時,標准偏差設為5%,那么過期時間會比較均勻的分布在3400~3800秒之間。如果我們的默認過期時間是7天,那么就會均勻分布在以7天為中心點的16小時內。這樣就可以很好的防止了緩存的雪崩問題。
未完待續
本文跟大家一起討論了緩存系統的常見穩定性問題,下一篇我來跟大家一起分析緩存的數據一致性問題。
所有這些問題的解決方法都已包含在 go-zero 微服務框架里,如果你想要更好的了解 go-zero 項目,歡迎前往官方網站上學習具體的示例。
視頻回放地址
項目地址
https://github.com/tal-tech/go-zero
歡迎使用 go-zero 並 star 支持我們!
微信交流群
關注『微服務實踐』公眾號並點擊 進群 獲取社區群二維碼。