摘要:緩存擊穿給緩存加一個(gè)過(guò)期時(shí)間,下次未命中緩存時(shí)再去從數(shù)據(jù)源獲取結(jié)果寫(xiě)入新的緩存,這個(gè)是后端開(kāi)發(fā)人員再熟悉不過(guò)的基操。
緩存擊穿
????給緩存加一個(gè)過(guò)期時(shí)間,下次未命中緩存時(shí)再去從數(shù)據(jù)源獲取結(jié)果寫(xiě)入新的緩存,這個(gè)是后端開(kāi)發(fā)人員再熟悉不過(guò)的基操。本人之前在做直播平臺(tái)活動(dòng)業(yè)務(wù)的時(shí)候,當(dāng)時(shí)帶著這份再熟練不過(guò)的自信,把復(fù)雜的數(shù)據(jù)庫(kù)鏈表語(yǔ)句寫(xiě)好,各種微服務(wù)之間調(diào)用撈數(shù)據(jù)最后算好的結(jié)果,丟進(jìn)了緩存然后設(shè)了一個(gè)過(guò)期時(shí)間,當(dāng)時(shí)噼里啪啦兩下寫(xiě)完代碼覺(jué)得穩(wěn)如鐵蛋,結(jié)果在活動(dòng)快結(jié)束之前,數(shù)據(jù)庫(kù)很友好的掛掉了。當(dāng)時(shí)回去查看監(jiān)控后發(fā)現(xiàn),是在活動(dòng)快結(jié)束前,大量用戶都在瘋狂的刷活動(dòng)頁(yè),導(dǎo)致緩存過(guò)期的瞬間有大量未命中緩存的請(qǐng)求直接打到數(shù)據(jù)庫(kù)上所導(dǎo)致的,所以這個(gè)經(jīng)典的問(wèn)題稍不注意還是害死人
????防緩存擊穿的方式有很多種,比如通過(guò)計(jì)劃任務(wù)來(lái)跟新緩存使得從前端過(guò)來(lái)的所有請(qǐng)求都是從緩存讀取等等。之前讀過(guò) groupCache的源碼,發(fā)現(xiàn)里面有一個(gè)很有意思的庫(kù),叫singleFlight, 因?yàn)間roupCache從節(jié)點(diǎn)上獲取緩存如果未命中,則會(huì)去其他節(jié)點(diǎn)尋找,其他節(jié)點(diǎn)還沒(méi)有的話再?gòu)臄?shù)據(jù)源獲取,所以這個(gè)步驟對(duì)于防擊穿非常有必要。singleFlight使得groupCache在多個(gè)并發(fā)請(qǐng)求對(duì)一個(gè)失效的key進(jìn)行源數(shù)據(jù)獲取時(shí),只讓其中一個(gè)得到執(zhí)行,其余阻塞等待到執(zhí)行的那個(gè)請(qǐng)求完成后,將結(jié)果傳遞給阻塞的其他請(qǐng)求達(dá)到防止擊穿的效果。
SingleFlight 使用Demo本文模擬一個(gè)數(shù)據(jù)源是從調(diào)用rpc獲取的場(chǎng)景
然后再模擬一百個(gè)并發(fā)請(qǐng)求在緩存失效的瞬間同時(shí)調(diào)用rpc訪問(wèn)源數(shù)據(jù)
效果
可以看到100個(gè)并發(fā)請(qǐng)求從源數(shù)據(jù)獲取時(shí),rpcServer端只收到了來(lái)自client 17的請(qǐng)求,而其余99個(gè)最后也都得到了正確的返回值。
在看完singleFlight的實(shí)際效果后,欣喜若狂,想必其實(shí)現(xiàn)應(yīng)該相當(dāng)復(fù)雜吧, 結(jié)果翻看源碼一看, 100行不到的代碼就解決了這么個(gè)業(yè)務(wù)痛點(diǎn), 不得不佩服。
package singlefilght import "sync" type Group struct { mu sync.Mutex m map[string]*Call // 對(duì)于每一個(gè)需要獲取的key有一個(gè)對(duì)應(yīng)的call } // call代表需要被執(zhí)行的函數(shù) type Call struct { wg sync.WaitGroup // 用于阻塞這個(gè)調(diào)用call的其他請(qǐng)求 val interface{} // 函數(shù)執(zhí)行后的結(jié)果 err error // 函數(shù)執(zhí)行后的error } func (g *Group) Do(key string, fn func()(interface{}, error)) (interface{}, error) { g.mu.Lock() if g.m == nil { g.m = make(map[string]*Call) } // 如果獲取當(dāng)前key的函數(shù)正在被執(zhí)行,則阻塞等待執(zhí)行中的,等待其執(zhí)行完畢后獲取它的執(zhí)行結(jié)果 if c, ok := g.m[key]; ok { g.mu.Unlock() c.wg.Wait() return c.val, c.err } // 初始化一個(gè)call,往map中寫(xiě)后就解 c := new(Call) c.wg.Add(1) g.m[key] = c g.mu.Unlock() // 執(zhí)行獲取key的函數(shù),并將結(jié)果賦值給這個(gè)Call c.val, c.err = fn() c.wg.Done() // 重新上鎖刪除key g.mu.Lock() delete(g.m, key) g.mu.Unlock() return c.val, c.err }
????對(duì)的沒(méi)看錯(cuò), 就這么100行不到的代碼就能解決緩存擊穿的問(wèn)題,這算是我寫(xiě)過(guò)最愉快的一篇博了,同時(shí)也推薦大家去讀一讀groupCache這個(gè)項(xiàng)目的源碼,會(huì)有更多驚喜的發(fā)現(xiàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/62074.html
摘要:前言分布式系統(tǒng)中經(jīng)常會(huì)出現(xiàn)某個(gè)基礎(chǔ)服務(wù)不可用造成整個(gè)系統(tǒng)不可用的情況這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng)為了應(yīng)對(duì)服務(wù)雪崩一種常見(jiàn)的做法是手動(dòng)服務(wù)降級(jí)而的出現(xiàn)給我們提供了另一種選擇服務(wù)雪崩效應(yīng)的定義服務(wù)雪崩效應(yīng)是一種因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的 前言 分布式系統(tǒng)中經(jīng)常會(huì)出現(xiàn)某個(gè)基礎(chǔ)服務(wù)不可用造成整個(gè)系統(tǒng)不可用的情況, 這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng). 為了應(yīng)對(duì)服務(wù)雪崩, 一種常見(jiàn)的做法是手動(dòng)服...
摘要:前言分布式系統(tǒng)中經(jīng)常會(huì)出現(xiàn)某個(gè)基礎(chǔ)服務(wù)不可用造成整個(gè)系統(tǒng)不可用的情況這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng)為了應(yīng)對(duì)服務(wù)雪崩一種常見(jiàn)的做法是手動(dòng)服務(wù)降級(jí)而的出現(xiàn)給我們提供了另一種選擇服務(wù)雪崩效應(yīng)的定義服務(wù)雪崩效應(yīng)是一種因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的 前言 分布式系統(tǒng)中經(jīng)常會(huì)出現(xiàn)某個(gè)基礎(chǔ)服務(wù)不可用造成整個(gè)系統(tǒng)不可用的情況, 這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng). 為了應(yīng)對(duì)服務(wù)雪崩, 一種常見(jiàn)的做法是手動(dòng)服...
摘要:解決方案通過(guò)布隆過(guò)濾器攔截。對(duì)空結(jié)果進(jìn)行緩存,但是過(guò)期時(shí)間很短,不超過(guò)分鐘。緩存雪崩介紹緩存雪崩是指設(shè)置緩存采用了相同的過(guò)期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請(qǐng)求全部轉(zhuǎn)發(fā)到,瞬間壓力過(guò)重雪崩。 緩存穿透 介紹 緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)被動(dòng)寫(xiě),并且處于容錯(cuò)考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫(xiě)入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢,失去了緩...
摘要:完善緩存擊穿問(wèn)題問(wèn)題描述,分布式場(chǎng)景中,有時(shí)候存在高并發(fā)訪問(wèn),比如秒殺活動(dòng)。在高并發(fā)訪問(wèn)下請(qǐng)求全部懟到數(shù)據(jù)庫(kù),可能導(dǎo)致數(shù)據(jù)庫(kù)掛掉,這就是緩存擊穿。緩存擊穿解決方案已經(jīng)能解決日常情況,但還是有一定提升的空間的。 做人、做程序,變則通,不變只能一直死循環(huán)下去 ————尼古斯拉 Docker安裝官方Redis 參考文章:Docker安裝官方Redis鏡像并啟用密碼認(rèn)證 拉取最新版...
閱讀 2519·2021-10-09 09:44
閱讀 3908·2021-09-22 15:43
閱讀 2998·2021-09-02 09:47
閱讀 2660·2021-08-12 13:29
閱讀 3942·2019-08-30 15:43
閱讀 1747·2019-08-30 13:06
閱讀 2250·2019-08-29 16:07
閱讀 2816·2019-08-29 15:23