快取系統穩定性 - 架構師峰會演講實錄

kevwan發表於2021-05-10

前言

大家好!我是萬俊峰,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 專案,歡迎前往官方網站上學習具體的示例。

視訊回放地址

ArchSummit架構師峰會-海量併發下的快取架構設計

專案地址

github.com/tal-tech/go-zero

歡迎使用 go-zero 並 star 支援我們!

微信交流群

關注『微服務實踐』公眾號並點選 進群 獲取社群群二維碼。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章