RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

聊聊緩存擊穿的解決方法

馬哥Linux運(yùn)維 ? 來源:博客園snail_lie ? 2024-10-23 13:54 ? 次閱讀

緩存擊穿,Redis中的某個(gè)熱點(diǎn)key不存在或者過期,但是此時(shí)有大量的用戶訪問該key。比如xxx直播間優(yōu)惠券搶購(gòu)、xxx商品活動(dòng),這時(shí)候大量用戶會(huì)在某個(gè)時(shí)間點(diǎn)一同訪問該熱點(diǎn)事件。但是可能由于某種原因,redis的這個(gè)熱點(diǎn)key沒有設(shè)置,或者過期了,那么這時(shí)候大量高并發(fā)對(duì)于該key的請(qǐng)求就得不到redis的響應(yīng),那么就會(huì)將請(qǐng)求直接打在DB服務(wù)器上,造成DB突刺,CPU和內(nèi)存瞬間被打滿,最終導(dǎo)致服務(wù)崩潰。

本人所負(fù)責(zé)的業(yè)務(wù)就存在這樣的場(chǎng)景,以直播間邀請(qǐng)榜單為例,顧名思義就是會(huì)查詢?cè)撝辈ラg實(shí)時(shí)的邀請(qǐng)人數(shù),統(tǒng)計(jì)前30名邀請(qǐng)人數(shù)最多的用戶展示在直播間里面,通過榜單去刺激C端用戶的分享參與熱情。下面一起分析下這個(gè)場(chǎng)景遇到的問題和解決方案。

問題1:
統(tǒng)計(jì)邀請(qǐng)榜單需要加載實(shí)時(shí)的,即我邀請(qǐng)一個(gè)人進(jìn)來,假設(shè)在前30名,那我不得上榜嗎?那問題來了,這種數(shù)據(jù)我是不是得實(shí)時(shí)去查數(shù)據(jù)庫呢?

解決方案:這種業(yè)務(wù),我們一般會(huì)設(shè)置一個(gè)短時(shí)間的緩存,比如30秒左右。也就是在緩存失效后,即30秒去查一次數(shù)據(jù)庫,不然數(shù)據(jù)庫肯定是頂不住的。

問題2:
我們常規(guī)的設(shè)置緩存的代碼邏輯可能是下面這種。(代碼片段錯(cuò)誤處理等細(xì)節(jié)請(qǐng)自行處理,這是一段精簡(jiǎn)版的代碼,主要介紹Redis的處理邏輯)

//step1:讀緩存,存在則返回結(jié)果
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr:     "localhost:6379",
Password: "123456",
DB:       0,
})

redisKey := "xxx_xxx_xxx" //邀請(qǐng)榜單數(shù)據(jù)的key

res, err := rdb.Get(ctx, redisKey).Result()
if err == nil {
return res
}

//step2:不存在緩存,讀DB
//此處省略,查DB的數(shù)據(jù),結(jié)果為res

//step3:設(shè)置緩存,并返回結(jié)果
args := redis.SetArgs{
TTL:  time.Second * 30,
Mode: "EX",
}
_, _ = rdb.SetArgs(ctx, redisKey, res, args).Result()

return res

這種代碼邏輯在并發(fā)量小的情況下是沒有任何問題的,事實(shí)上我平時(shí)寫一些業(yè)務(wù),基本上就把它當(dāng)成一個(gè)“公式”來用,用的非常多。然而,在一些高并發(fā)的場(chǎng)景下,這種邏輯就會(huì)出現(xiàn)問題。試想一下這個(gè)場(chǎng)景:假如某個(gè)大直播(用戶量巨大)是在晚上8點(diǎn)開播,那么8點(diǎn)一到,那個(gè)瞬間就會(huì)有大量的C端用戶進(jìn)入直播間,去調(diào)用后端的接口,假如此時(shí)接口的Redis緩存已經(jīng)過期或者不存在,那么這一刻就會(huì)有大量的請(qǐng)求落到DB上,可想而知這一刻DB的壓力是多么巨大(這誰頂?shù)米“。?strong>這就是一個(gè)典型的緩存擊穿的業(yè)務(wù)場(chǎng)景。
那么我們需要怎么做,才能讓我們的服務(wù)抵抗住瞬時(shí)的請(qǐng)求洪峰呢?

解決方案:
解決緩存擊穿的常見方法有幾種:
1、設(shè)置該key永不過期,那么就不會(huì)存在緩存失效、過期等問題。但這種方法很明顯不適合我這種場(chǎng)景,因?yàn)槲疑厦嫣岬竭^,我這個(gè)key值存的是邀請(qǐng)榜單的數(shù)據(jù),是動(dòng)態(tài)更新的,在直播中,這個(gè)榜單的數(shù)據(jù)是會(huì)變化的,所以只能設(shè)30秒的緩存時(shí)間。該方案行不通。

2、人工干預(yù)該key,比如寫一個(gè)腳本去定時(shí)讀DB數(shù)據(jù),然后更新這個(gè)key,然后業(yè)務(wù)側(cè)(對(duì)接前端的接口)只能通過讀該key的緩存去獲取結(jié)果數(shù)據(jù),而不能直接讀DB。這樣也能解決問題,但是貌似維護(hù)成本有點(diǎn)高,而且業(yè)務(wù)側(cè)不能讀DB也很不靈活,你想下如果每個(gè)熱點(diǎn)key都這樣去設(shè)置維護(hù),那估計(jì)會(huì)很煩吧。該方案也行不通。

3、使用互斥鎖,即在緩存失效的時(shí)候,只有一個(gè)請(qǐng)求可以獲取到互斥鎖,然后去查DB,最后重建緩存。這種方案就能很好地解決緩存擊穿這個(gè)問題,也是我在工作中用來應(yīng)對(duì)緩存擊穿問題的最常用的方案。下面是精簡(jiǎn)版代碼:

//step1:讀緩存,存在則返回結(jié)果
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr:     "localhost:6379",
Password: "123456",
DB:       0,
})

redisKey := "xxx_xxx_xxx" //邀請(qǐng)榜單數(shù)據(jù)的key

res, err := rdb.Get(ctx, redisKey).Result()
if err == nil {
return res
}

//step2:不存在緩存,加互斥鎖,讀緩存
lockKey := "yyy_yyy_yyy" //互斥鎖的key

argsLock := redis.SetArgs{
TTL:  time.Second * 3,
Mode: "NX", //不存在時(shí)才執(zhí)行
}

_, err = rdb.SetArgs(ctx, lockKey, "1", argsLock).Result()
if err != nil { //獲取互斥鎖失敗
for i := 0; i < 3; i++ { //重復(fù)三次去讀緩存值
res, errRetry := rdb.Get(ctx, redisKey).Result()
if errRetry == nil { //重試讀緩存成功,則返回結(jié)果
return res 
}
time.Sleep(10 * time.Millisecond) //這里睡眠時(shí)間根據(jù)業(yè)務(wù)來定,取的是另一個(gè)線程從讀數(shù)據(jù)庫到設(shè)置緩存成功的大概時(shí)間區(qū)間
}
return nil //如果循環(huán)三次,都讀不到緩存,則返回空結(jié)果
}

//step3:獲取互斥鎖成功,則表明當(dāng)前的線程/協(xié)程擁有查DB的權(quán)力
//此處省略,查DB的數(shù)據(jù),結(jié)果為res

//step4:設(shè)置緩存,刪除互斥鎖,并返回結(jié)果
args := redis.SetArgs{
TTL:  time.Second * 30,
Mode: "EX",
}
_, _ = rdb.SetArgs(ctx, redisKey, res, args).Result()

rdb.Del(ctx, lockKey) //刪除互斥鎖

return res

以上就是個(gè)人在線上的一些項(xiàng)目面對(duì)緩存擊穿問題,所做的一些處理方案了。當(dāng)然這個(gè)方案也不是完美的,例如當(dāng)獲取到互斥鎖的當(dāng)前線程/協(xié)程,出現(xiàn)異常,導(dǎo)致設(shè)置緩存失敗,那么其他線程/協(xié)程就重試3次可能都獲取不到正常結(jié)果,最后返回了一個(gè)空結(jié)果給前端。感興趣的朋友可以想想這個(gè)方案還有什么問題,然后能怎么優(yōu)化,歡迎指出

一個(gè)人可以被毀滅,但不可以被打敗。

鏈接:https://www.cnblogs.com/lmz-blogs/p/18173813

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    9123

    瀏覽量

    85322
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    239

    瀏覽量

    26669
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    374

    瀏覽量

    10871

原文標(biāo)題:go高并發(fā)之路——緩存擊穿

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙OpenHarmony:【常見編譯問題和解決方法

    常見編譯問題和解決方法
    的頭像 發(fā)表于 05-11 16:09 ?2142次閱讀

    阻容降壓 剛一上電 穩(wěn)壓管就擊穿了,然后限流的線繞電阻也燒了,請(qǐng)問大佬這是怎么回事,有什么解決方法嗎。

    `阻容降壓 剛一上電 穩(wěn)壓管ZD1和2就擊穿了,然后限流的線繞電阻R20也燒了,請(qǐng)問大佬這是怎么回事,有什么解決方法嗎。`
    發(fā)表于 04-26 16:38

    聊聊環(huán)形緩存在單片機(jī)程序中的使用

    片頭因?yàn)榄h(huán)形緩存在單片機(jī)程序中的使用是非常有效的,非常有用的,關(guān)于這個(gè)話題在此專門開一文章來聊聊這個(gè)話題。環(huán)形緩存的用途主要是來緩存數(shù)據(jù),而需要緩存
    發(fā)表于 12-06 08:29

    短波通信盲區(qū)現(xiàn)象解決方法介紹

    短波通信盲區(qū)現(xiàn)象解決方法介紹短波通信盲區(qū)現(xiàn)象解決方法介紹短波通信盲區(qū)現(xiàn)象解決方法介紹
    發(fā)表于 11-10 17:13 ?5次下載

    sdwebimage清除緩存方法

    清除通過SDWebImage進(jìn)行的緩存;Sdwebimage手動(dòng)清除緩存方法;iOS SDWebImage清空緩存方法.
    發(fā)表于 11-09 14:38 ?3613次閱讀
    sdwebimage清除<b class='flag-5'>緩存</b><b class='flag-5'>方法</b>

    電容擊穿是開路還是短路_電容擊穿原因是什么

    本文開始闡述了電容擊穿的概念和電容器被擊穿的條件,其次分析了電容擊穿后是開路還是短路,最后介紹了電容擊穿的原因以及避免介質(zhì)擊穿
    發(fā)表于 03-27 18:21 ?6w次閱讀

    內(nèi)存安裝和使用常見問題的解決方法資料分析

    自銳龍平臺(tái)發(fā)布以來,AMD CPU憑借超高的性價(jià)比迅速崛起,如今整個(gè)市場(chǎng)已成為AMD和Intel平分秋色“五五開”的局面。但是盡管AMD銳龍平臺(tái)來勢(shì)洶洶,其內(nèi)存控制器一直處于有待完善的水平。所以今天小編就藉此機(jī)會(huì)簡(jiǎn)單聊聊關(guān)于內(nèi)存常見問題的解決方法。
    的頭像 發(fā)表于 12-15 11:11 ?4387次閱讀

    如何設(shè)計(jì)一個(gè)緩存系統(tǒng)?

    設(shè)計(jì)一個(gè)緩存系統(tǒng),不得不要考慮的問題就是:緩存穿透、緩存擊穿與失效時(shí)的雪崩效應(yīng)。 緩存穿透 緩存
    的頭像 發(fā)表于 02-08 11:40 ?2920次閱讀

    聊聊緩存數(shù)據(jù)庫一致性

    在云服務(wù)中,緩存是極其重要的一點(diǎn)。所謂緩存,其實(shí)是一個(gè)高速數(shù)據(jù)存儲(chǔ)層。當(dāng)緩存存在后,日后再次請(qǐng)求該數(shù)據(jù)就會(huì)直接訪問緩存,提升數(shù)據(jù)訪問的速度。
    的頭像 發(fā)表于 01-30 17:41 ?769次閱讀

    如何在SpringBoot中解決Redis的緩存穿透等問題

    今天給大家介紹一下如何在SpringBoot中解決Redis的緩存穿透、緩存擊穿、緩存雪崩的問題。
    的頭像 發(fā)表于 04-28 11:35 ?724次閱讀

    聊聊分頁列表緩存設(shè)計(jì)

    這是最簡(jiǎn)單易懂的方案,我們按照不同的分頁條件查詢出結(jié)果后,直接緩存分頁結(jié)果 。
    的頭像 發(fā)表于 06-06 18:25 ?719次閱讀
    <b class='flag-5'>聊聊</b>分頁列表<b class='flag-5'>緩存</b>設(shè)計(jì)

    聊聊本地緩存和分布式緩存

    本地緩存 :應(yīng)用中的緩存組件,緩存組件和應(yīng)用在同一進(jìn)程中,緩存的讀寫非常快,沒有網(wǎng)絡(luò)開銷。但各應(yīng)用或集群的各節(jié)點(diǎn)都需要維護(hù)自己的單獨(dú)緩存,無
    發(fā)表于 06-11 15:12 ?825次閱讀
    <b class='flag-5'>聊聊</b>本地<b class='flag-5'>緩存</b>和分布式<b class='flag-5'>緩存</b>

    Redis緩存預(yù)熱+緩存雪崩+緩存擊穿+緩存穿透要點(diǎn)簡(jiǎn)析

    緩存預(yù)熱就是系統(tǒng)上線后,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。
    的頭像 發(fā)表于 12-25 09:41 ?901次閱讀
    Redis<b class='flag-5'>緩存</b>預(yù)熱+<b class='flag-5'>緩存</b>雪崩+<b class='flag-5'>緩存</b><b class='flag-5'>擊穿</b>+<b class='flag-5'>緩存</b>穿透要點(diǎn)簡(jiǎn)析

    MOS管擊穿原理分析、原因及解決方法

    MOS管(金屬-氧化物-半導(dǎo)體場(chǎng)效應(yīng)管)是一種常用的電子元件,在電路中起著開關(guān)、放大等重要作用。然而,在某些情況下,MOS管可能會(huì)發(fā)生擊穿現(xiàn)象,導(dǎo)致其失效。擊穿原理主要涉及電場(chǎng)強(qiáng)度、電荷積累、熱量等因素。
    的頭像 發(fā)表于 10-09 11:54 ?4077次閱讀

    mac的常見問題解決方法

    Mac常見問題解決方法 1. 系統(tǒng)啟動(dòng)緩慢 問題描述: 啟動(dòng)Mac時(shí),系統(tǒng)啟動(dòng)緩慢,甚至出現(xiàn)卡頓現(xiàn)象。 解決方法: 檢查啟動(dòng)項(xiàng)目: 打開系統(tǒng)偏好設(shè)置中的“用戶與群組”,點(diǎn)擊“登錄項(xiàng)”,移除不必要
    的頭像 發(fā)表于 12-19 15:02 ?141次閱讀
    RM新时代网站-首页