緩存系列:緩存穿透的解決思路
大家好,我是李哥。

上次我們討論了在分布式系統(tǒng)下的緩存架構體系,從瀏覽器緩存到客戶端緩存,再到CDN緩存,再到反向代理緩存,再到本地緩存,再到分布式緩存。整個鏈路中有非常多的緩存。
如果面試官問你說:給你一個機會,你有什么辦法能夠繞過這么多層緩存,將我們的慢設備擊垮呢?(這里的慢設備一般指基于磁盤進行存儲的關系型數(shù)據(jù)庫,如MySQL)
難道這就是傳說中的:「即使敵眾我寡,末將也能從百萬叢軍中取敵將首級!」
這便是我們今天的主題:緩存穿透
什么是緩存穿透?
我們知道,緩存的工作原理是先從緩存中獲取數(shù)據(jù),如果有數(shù)據(jù)則直接返回給用戶,如果沒有數(shù)據(jù)則從慢速設備上讀取實際數(shù)據(jù)并且將數(shù)據(jù)放入緩存。同步緩存就像這樣:
或者使用異步的方式去同步緩存就像這樣:
但是,如果緩存中和慢設備中一直都沒有數(shù)據(jù)的話,是什么流程呢?
沒錯,如果緩存和數(shù)據(jù)庫都沒有的數(shù)據(jù),請求仍然會先經(jīng)過緩存再經(jīng)過數(shù)據(jù)庫,下次請求依然是同樣的路徑,這便是緩存穿透。
小結(jié):緩存穿透,是指請求每次都要經(jīng)過緩存,去訪問慢設備,而慢設備又沒有數(shù)據(jù),在并發(fā)訪問的情況有可能將慢設備擊垮。
緩存穿透可能帶來哪些問題?
我們知道了緩存穿透的場景后,其次我們要了解它的痛點是什么?
在高并發(fā)的情況下有可能將慢設備擊垮;
每次請求都要經(jīng)過無效的緩存層,請求相對較慢;
緩存穿透的解決思路有哪些?
問題1的解決思路:
高并發(fā)會將慢設備擊垮,那么我們在這里的解決思路可以是讓高并發(fā)變成低并發(fā),讓慢設備變得足夠強大可以抗住足夠的壓力不被擊垮。
高并發(fā)轉(zhuǎn)換為低并發(fā)
如何讓高并發(fā)變成低并發(fā)呢?
此刻你的思路沒錯,加鎖。這種情況下可以是本地鎖和分布式鎖。本地鎖指的是一個服務只允許N個線程同時訪問慢設備(N代表N個實例),分布式鎖指的是在永遠只允許一個線程同時訪問慢設備。當然了,也可以使用一些限流算法來玩。比如計數(shù)器法、令牌桶算法、漏桶算法等,我們今天的主題并不是它,暫且跳過,后續(xù)會有專門的文章來講解。
回到正題。
服務實例數(shù)量不多的話可以使用本地鎖,畢竟本地鎖比分布式鎖快。
服務實例數(shù)量較多的話則需要使用分布式鎖來解決,進行流量防護。
但是如果數(shù)據(jù)一直不存在的話,仍然是有這種無效的請求,所以,在這一個線程訪問慢設備的時候,如果數(shù)據(jù)為空,我們就約定一個數(shù)據(jù)放入緩存,如果數(shù)據(jù)為約定數(shù)據(jù),則下次請求直接返回沒有數(shù)據(jù)即可。示例圖如下:
(這張圖建議好好理解)
提高慢設備高可用
慢設備我們一般指的是DB,我們在這個場景中如何提升DB的高可用而不被擊垮呢?
我們有以下兩種思路:
我們在DB側(cè)使配置最大線程數(shù),用固定線程數(shù)對其進行限流處理;
或者是我們將DB做成主從數(shù)據(jù)庫,讀數(shù)據(jù)均勻的散布在從庫上,并且從庫讓我們可以無限水平擴容。
問題2的解決思路:
問題2:每次請求都要經(jīng)過無效的緩存層,請求相對較慢。
沒錯,細心的你一定發(fā)現(xiàn)了,我們在討論《高并發(fā)轉(zhuǎn)換為低并發(fā)》其實就已經(jīng)解決了這個問題。
另外一種思考方式:
為什么會存在這個情況?(緩存無數(shù)據(jù),慢設備無數(shù)據(jù),但是又存在這樣的請求)
我的猜想有:
攻擊者!
數(shù)據(jù)被修改或刪除,數(shù)據(jù)變更后,原來的查詢路徑無法獲取數(shù)據(jù);
慢設備故障導致數(shù)據(jù)丟失+緩存失效
那么如果是攻擊者的話,我們的應對辦法可以是請求達到閾值后封禁IP和對查詢內(nèi)容進行過濾,比如id≤0一定不存在則可以過濾。
如果是數(shù)據(jù)更新導致原路徑無法查詢,再加上高并發(fā)導致慢設備宕機,所以這種情況的應對辦法應該是盡可能的減少熱點數(shù)據(jù)更新頻率+熱點數(shù)據(jù)異步刷新保證熱點數(shù)據(jù)在緩存中不過期。
如果是慢設備故障的話,那就沒辦法了,超出程序員應該有的思考范圍了,這種情況下應該是做同城雙活、異地多活等架構來保證高可用性。像阿里的兩地三中心,三地五中心等架構,別著急,后面會詳細介紹的,點個關注吧。
可以關注我的公中號:李哥技術
大家好,我是李哥。
上次我們討論了在分布式系統(tǒng)下的緩存架構體系,從瀏覽器緩存到客戶端緩存,再到CDN緩存,再到反向代理緩存,再到本地緩存,再到分布式緩存。整個鏈路中有非常多的緩存。
如果面試官問你說:給你一個機會,你有什么辦法能夠繞過這么多層緩存,將我們的慢設備擊垮呢?(這里的慢設備一般指基于磁盤進行存儲的關系型數(shù)據(jù)庫,如MySQL)
難道這就是傳說中的:「即使敵眾我寡,末將也能從百萬叢軍中取敵將首級!」
這便是我們今天的主題:緩存穿透
什么是緩存穿透?
我們知道,緩存的工作原理是先從緩存中獲取數(shù)據(jù),如果有數(shù)據(jù)則直接返回給用戶,如果沒有數(shù)據(jù)則從慢速設備上讀取實際數(shù)據(jù)并且將數(shù)據(jù)放入緩存。同步緩存就像這樣:
或者使用異步的方式去同步緩存就像這樣:
但是,如果緩存中和慢設備中一直都沒有數(shù)據(jù)的話,是什么流程呢?
沒錯,如果緩存和數(shù)據(jù)庫都沒有的數(shù)據(jù),請求仍然會先經(jīng)過緩存再經(jīng)過數(shù)據(jù)庫,下次請求依然是同樣的路徑,這便是緩存穿透。
小結(jié):緩存穿透,是指請求每次都要經(jīng)過緩存,去訪問慢設備,而慢設備又沒有數(shù)據(jù),在并發(fā)訪問的情況有可能將慢設備擊垮。
緩存穿透可能帶來哪些問題?
我們知道了緩存穿透的場景后,其次我們要了解它的痛點是什么?
在高并發(fā)的情況下有可能將慢設備擊垮;
每次請求都要經(jīng)過無效的緩存層,請求相對較慢;
緩存穿透的解決思路有哪些?
問題1的解決思路:
高并發(fā)會將慢設備擊垮,那么我們在這里的解決思路可以是讓高并發(fā)變成低并發(fā),讓慢設備變得足夠強大可以抗住足夠的壓力不被擊垮。
如何讓高并發(fā)變成低并發(fā)呢?
此刻你的思路沒錯,加鎖。這種情況下可以是本地鎖和分布式鎖。本地鎖指的是一個服務只允許N個線程同時訪問慢設備(N代表N個實例),分布式鎖指的是在永遠只允許一個線程同時訪問慢設備。當然了,也可以使用一些限流算法來玩。比如計數(shù)器法、令牌桶算法、漏桶算法等,我們今天的主題并不是它,暫且跳過,后續(xù)會有專門的文章來講解。
回到正題。
服務實例數(shù)量不多的話可以使用本地鎖,畢竟本地鎖比分布式鎖快。
服務實例數(shù)量較多的話則需要使用分布式鎖來解決,進行流量防護。
但是如果數(shù)據(jù)一直不存在的話,仍然是有這種無效的請求,所以,在這一個線程訪問慢設備的時候,如果數(shù)據(jù)為空,我們就約定一個數(shù)據(jù)放入緩存,如果數(shù)據(jù)為約定數(shù)據(jù),則下次請求直接返回沒有數(shù)據(jù)即可。示例圖如下:
(這張圖建議好好理解)
慢設備我們一般指的是DB,我們在這個場景中如何提升DB的高可用而不被擊垮呢?
我們有以下兩種思路:
我們在DB側(cè)使配置最大線程數(shù),用固定線程數(shù)對其進行限流處理;
或者是我們將DB做成主從數(shù)據(jù)庫,讀數(shù)據(jù)均勻的散布在從庫上,并且從庫讓我們可以無限水平擴容。
問題2的解決思路:
問題2:每次請求都要經(jīng)過無效的緩存層,請求相對較慢。
沒錯,細心的你一定發(fā)現(xiàn)了,我們在討論《高并發(fā)轉(zhuǎn)換為低并發(fā)》其實就已經(jīng)解決了這個問題。
另外一種思考方式:
為什么會存在這個情況?(緩存無數(shù)據(jù),慢設備無數(shù)據(jù),但是又存在這樣的請求)
我的猜想有:
攻擊者!
數(shù)據(jù)被修改或刪除,數(shù)據(jù)變更后,原來的查詢路徑無法獲取數(shù)據(jù);
慢設備故障導致數(shù)據(jù)丟失+緩存失效
那么如果是攻擊者的話,我們的應對辦法可以是請求達到閾值后封禁IP和對查詢內(nèi)容進行過濾,比如id≤0一定不存在則可以過濾。
如果是數(shù)據(jù)更新導致原路徑無法查詢,再加上高并發(fā)導致慢設備宕機,所以這種情況的應對辦法應該是盡可能的減少熱點數(shù)據(jù)更新頻率+熱點數(shù)據(jù)異步刷新保證熱點數(shù)據(jù)在緩存中不過期。
如果是慢設備故障的話,那就沒辦法了,超出程序員應該有的思考范圍了,這種情況下應該是做同城雙活、異地多活等架構來保證高可用性。像阿里的兩地三中心,三地五中心等架構,別著急,后面會詳細介紹的,點個關注吧。
可以關注我的公中號:李哥技術
總結(jié)
緩存穿透是指:緩存和慢設備都沒有數(shù)據(jù),加上高并發(fā)的請求,慢設備扛不住導致宕機。
緩存穿透的解決方案:
如果是攻擊者,封禁IP
提前做數(shù)據(jù)過濾,減少慢設備訪問次數(shù)
當緩存無數(shù)據(jù)時,訪問慢設備之前獲取一把鎖,減少慢設備并發(fā)訪問
做好高可用架構設計
好了,本期就討論到這里,感謝閱讀。
既然都看到這里了,你的+在看就是對我最大的支持。
Java 分布式 分布式緩存服務 Redis 架構設計 緩存
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。