緩存,你真的用對了么?
緩存,是互聯(lián)網(wǎng)分層架構(gòu)中,非常重要的一個部分,通常用它來降低數(shù)據(jù)庫壓力,提升系統(tǒng)整體性能,縮短訪問時間。
有架構(gòu)師說“緩存是萬金油,哪里有問題,加個緩存,就能優(yōu)化”,緩存的濫用,可能會導致一些錯誤用法。
緩存,你真的用對了么?
誤用一:把緩存作為服務與服務之間傳遞數(shù)據(jù)的媒介
如上圖:
- 服務1和服務2約定好key和value,通過緩存?zhèn)鬟f數(shù)據(jù)
- 服務1將數(shù)據(jù)寫入緩存,服務2從緩存讀取數(shù)據(jù),達到兩個服務通信的目的
該方案存在的問題是:
- 數(shù)據(jù)管道,數(shù)據(jù)通知場景,MQ更加適合
- 多個服務關(guān)聯(lián)同一個緩存實例,會導致服務耦合
誤用二:使用緩存未考慮雪崩
常規(guī)的緩存玩法,如上圖:
- 服務先讀緩存,緩存***則返回
- 緩存不***,再讀數(shù)據(jù)庫
什么時候會產(chǎn)生雪崩?
答:如果緩存掛掉,所有的請求會壓到數(shù)據(jù)庫,如果未提前做容量預估,可能會把數(shù)據(jù)庫壓垮(在緩存恢復之前,數(shù)據(jù)庫可能一直都起不來),導致系統(tǒng)整體不可服務。
如何應對潛在的雪崩?
答:提前做容量預估,如果緩存掛掉,數(shù)據(jù)庫仍能扛住,才能執(zhí)行上述方案。
否則,就要進一步設計。
常見方案一:高可用緩存
如上圖:使用高可用緩存集群,一個緩存實例掛掉后,能夠自動做故障轉(zhuǎn)移。
常見方案二:緩存水平切分
如上圖:使用緩存水平切分,一個緩存實例掛掉后,不至于所有的流量都壓到數(shù)據(jù)庫上。
誤用三:調(diào)用方緩存數(shù)據(jù)
如上圖:
- 服務提供方緩存,向調(diào)用方屏蔽數(shù)據(jù)獲取的復雜性(這個沒問題)
- 服務調(diào)用方,也緩存一份數(shù)據(jù),先讀自己的緩存,再決定是否調(diào)用服務(這個有問題)
該方案存在的問題是:
- 調(diào)用方需要關(guān)注數(shù)據(jù)獲取的復雜性
- 更嚴重的,服務修改db里的數(shù)據(jù),淘汰了服務cache之后,難以通知調(diào)用方淘汰其cache里的數(shù)據(jù),從而導致數(shù)據(jù)不一致
- 有人說,服務可以通過MQ通知調(diào)用方淘汰數(shù)據(jù),額,難道下游的服務要依賴上游的調(diào)用方,分層架構(gòu)設計不是這么玩的
誤用四:多服務共用緩存實例
如上圖:
- 服務A和服務B共用一個緩存實例(不是通過這個緩存實例交互數(shù)據(jù))
該方案存在的問題是:
- 可能導致key沖突,彼此沖掉對方的數(shù)據(jù)
- 畫外音:可能需要服務A和服務B提前約定好了key,以確保不沖突,常見的約定方式是使用namespace:key的方式來做key。
- 不同服務對應的數(shù)據(jù)量,吞吐量不一樣,共用一個實例容易導致一個服務把另一個服務的熱數(shù)據(jù)擠出去
- 共用一個實例,會導致服務之間的耦合,與微服務架構(gòu)的“數(shù)據(jù)庫,緩存私有”的設計原則是相悖的
建議的玩法是:
如上圖:各個服務私有化自己的數(shù)據(jù)存儲,對上游屏蔽底層的復雜性。
總結(jié)
緩存使用小技巧:
- 服務與服務之間不要通過緩存?zhèn)鬟f數(shù)據(jù)
- 如果緩存掛掉,可能導致雪崩,此時要做高可用緩存,或者水平切分
- 調(diào)用方不宜再單獨使用緩存存儲服務底層的數(shù)據(jù),容易出現(xiàn)數(shù)據(jù)不一致,以及反向依賴
- 不同服務,緩存實例要做垂直拆分
【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】