golang?防緩存擊穿singleflight的實(shí)現(xiàn)
一、什么是緩存擊穿
當(dāng)一個(gè)key是熱點(diǎn)key時(shí),一般會(huì)做緩存來抗大量并發(fā),但當(dāng)緩存失效的一瞬間,這些大量的并發(fā)請求會(huì)擊穿緩存,直接請求數(shù)據(jù)庫
為了避免緩存擊穿,一種解決方法可以設(shè)置緩存永不過期,另一種可以使用golang的包 singleflight golang.org/x/sync/singleflight
二、原理
多個(gè)并發(fā)請求對一個(gè)失效key進(jìn)行數(shù)據(jù)獲取時(shí),只會(huì)有其中一個(gè)去直接獲取數(shù)據(jù),其它請求會(huì)阻塞等待第一個(gè)請求返回給它們結(jié)果
三、實(shí)現(xiàn)
package singleflight
import (
"sync"
)
var WaitCount int
var DirectCount int
type Caller struct {
val interface{}
err error
wg sync.WaitGroup
}
type Group struct {
mu sync.RWMutex
m map[string]*Caller
}
func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
g.mu.Lock()
if g.m == nil {
g.m = make(map[string]*Caller)
}
c, ok := g.m[key]
if ok {
//阻塞等待其它已經(jīng)執(zhí)行此操作的返回結(jié)果
g.mu.Unlock()
c.wg.Wait()
WaitCount++
return c.val, c.err
}
//直接請求獲取數(shù)據(jù)
c = &Caller{}
g.m[key] = c
c.wg.Add(1)
g.mu.Unlock()
c.val, c.err = fn()
c.wg.Done()
g.mu.Lock()
delete(g.m, key)
g.mu.Unlock()
DirectCount++
return c.val, c.err
}測試:
func TestGroup_Do(t *testing.T) {
sg := &Group{}
wg := sync.WaitGroup{}
for i := 0; i < 10000; i++ {
fn := func() (interface{}, error) {
return i, nil
}
wg.Add(1)
go func() {
defer wg.Done()
got, err := sg.Do("test-key", fn)
_, _ = got, err
//t.Log("got:", i)
}()
}
wg.Wait()
fmt.Println("waitCount:", WaitCount)
fmt.Println("DirectCount:", DirectCount)
}輸出:
waitCount: 8323
DirectCount: 1401
到此這篇關(guān)于golang 防緩存擊穿singleflight的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang 防緩存擊穿singleflight 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解golang consul-grpc 服務(wù)注冊與發(fā)現(xiàn)
這篇文章主要介紹了詳解golang consul-grpc 服務(wù)注冊與發(fā)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06
Go語言Gin框架前后端分離項(xiàng)目開發(fā)實(shí)例
本文主要介紹了Go語言Gin框架前后端分離項(xiàng)目開發(fā)工程化實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11
Go語言模型:string的底層數(shù)據(jù)結(jié)構(gòu)與高效操作詳解
這篇文章主要介紹了Go語言模型:string的底層數(shù)據(jù)結(jié)構(gòu)與高效操作詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
一文帶你了解Go語言中函數(shù)設(shè)計(jì)的實(shí)踐示例
良好設(shè)計(jì)的函數(shù)具有清晰的職責(zé)和邏輯結(jié)構(gòu),提供準(zhǔn)確的命名和適當(dāng)?shù)膮?shù)控制,下面我們將一一描述函數(shù)設(shè)計(jì)時(shí)能夠遵循的最佳實(shí)踐,希望對大家有所幫助2023-06-06
Golang定時(shí)任務(wù)框架GoCron的源碼分析
本文主要介紹了Golang定時(shí)任務(wù)框架GoCron的源碼分析,原生的gocron存在一些問題,如任務(wù)列表維護(hù)不當(dāng)、并發(fā)操作不可預(yù)測等,經(jīng)過改進(jìn)的gocron解決了這些問題,感興趣的可以了解一下2025-03-03
go select編譯期的優(yōu)化處理邏輯使用場景分析
select 是 Go 中的一個(gè)控制結(jié)構(gòu),類似于用于通信的 switch 語句。每個(gè) case 必須是一個(gè)通信操作,要么是發(fā)送要么是接收。接下來通過本文給大家介紹go select編譯期的優(yōu)化處理邏輯使用場景分析,感興趣的朋友一起看看吧2021-06-06
golang并發(fā)執(zhí)行的幾種方式小結(jié)
本文主要介紹了golang并發(fā)執(zhí)行的幾種方式小結(jié),主要包括了Channel,WaitGroup ,Context,使用這三種機(jī)制中的一種或者多種可以達(dá)到并發(fā)控制很好的效果,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08

