singleflight
包主要是用来做并发控制,整个包的核心代码不到100行,充分利用到了map
和WaitGroup
的特性。
常见的场景比如防止 缓存击穿
,我们可以来模拟一下这种场景:
缓存击穿:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
package main
import (
"errors"
"log"
"sync"
"golang.org/x/sync/singleflight"
)
var errorNotExist = errors.New("not exist")
func main() {
var wg sync.WaitGroup
wg.Add(10)
//模拟10个并发
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
data, err := getData("key")
if err != nil {
log.Print(err)
return
}
log.Println(data)
}()
}
wg.Wait()
}
//获取数据
func getData(key string) (string, error) {
data, err := getDataFromCache(key)
if err == errorNotExist {
//模拟从db中获取数据
data, err = getDataFromDB(key)
if err != nil {
log.Println(err)
return "", err
}
//TOOD: set cache
} else if err != nil {
return "", err
}
return data, nil
}
//模拟从cache中获取值,cache中无该值
func getDataFromCache(key string) (string, error) {