简介
缓存击穿:缓存失效时,有大量并发请求过来。大量请求从缓存上拿不到数据,请求压力全部打到数据库上。
场景1:活动结束前。为了完成活动任务,请求活动配置数据请求一般会有爆发性增长。当你的服务没有做防止缓存击穿的话,就有可能让你的数据库宕机
singleFlight包
singleFlight会将对同一个key的所有请求,变成一个请求,所有请求共享一个请求返回的数据。
场景:活动尾声大量并发请求获取活动配置数据。设置该活动key为activity_key,所有请求都会开个goroutine处理。所有请求都通过DO函数绑定 key和fn回调函数进行处理。singleFlight内部利用一个map和一个call对象。实现了所有请求共享一个请求返回的数据。
singleFlight源码解析
type call struct {
wg sync.WaitGroup // 并发调用group.Do时,控制fn的调用。
// These fields are written once before the WaitGroup is done
// and are only read after the WaitGroup is done.
val interface{
}
err error
// forgotten indicates whether Forget was called with this call's key
// while the call was still in flight.
forgotten bool // key是否存在group的map
// These fields are read and written with the singleflight
// mutex held before the WaitGroup is done, and are read but
// not written after the WaitGroup is done.
dups int // 并发调用key fn的数量
chans []chan<- Result //这里的Chan都是带缓存的chan,保存的是fn的结果
}
// Group represents a class of work and forms a namespace in
// which units of work can be executed with duplicate suppression.
type Group struct {
mu sync.Mutex // protects m
m map[string]*call // lazily initialized
}
// Result holds the results of Do, so they can be passed
// on a channel.
type Result struct {
Val interface{
} // fn的返回值
Err error
Shared bool //是否有并发请求 共享返回结果。
}
// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
// original to complete and receives the same results.
// The return value shared indicates whether v was given to multiple callers.
func (g *Group) Do(key string, fn func() (interface{
}, error))