欢迎关注我的wechat公众号:程序员技术成长之路
欢迎投递简历,可以帮忙内推
什么是singleflight
Singleflight是Google开源的一个Go语言库,主要用于控制对共享资源的重复请求,防止服务器被同时高并发访问所引发的"雪崩"问题。具体来说,当多个相同的请求(例如访问同一个数据或地址)在同一时间发生时,Singleflight会将这些请求合并为一个。实际上,只有一个请求会被执行,然后这个请求的结果将被所有其他的请求共享。
这个库的主要应用场景是缓存系统。例如,当有大量用户同时请求同一资源时,如果没有Singleflight,服务器可能需要执行大量的数据库查询或其他高负荷操作。但有了Singleflight,服务器只需执行一次查询或操作,然后将结果返回给所有请求。这大大减轻了服务器的负载。
主要作用
Singleflight 的主要作用是防止对共享资源的多次重复请求,特别是在高并发的场景中。这样可以避免不必要的重复工作,减轻服务器负载,提高系统的性能和效率。 当有多个相同的请求同时发生时,Singleflight 会把这些请求合并为一个,只执行一次请求操作(如数据库查询,HTTP 请求等),然后把这个结果共享给所有的请求。这就避免了相同的请求被重复执行多次,提高了系统的性能。 此外,Singleflight 还可以帮助抑制雪崩效应,当系统中某一部分因过载而出现问题时,不会影响到整个系统的运行。
Go如何使用
var g singleflight.Group
func someExpensiveOperation() (interface{}, error) {
time.Sleep(1 * time.Second)
return "foo", nil
}
func main() {
for i := 0; i < 5; i++ {
go func() {
v, err, _ := g.Do("some_key", someExpensiveOperation)
if err != nil {
fmt.Printf("error: %v\n", err)
return
}
fmt.Printf("got: %v\n", v)
}()
}
time.Sleep(2 * time.Second)
}
在这个例子中,someExpensiveOperation
代表一项消耗很大的操作,比如一个复杂的数据库查询或者一个网络请求。当这个函数被并发调用多次时,singleflight
会保证这个函数只执行一次,然后各个并发的调用者将获得相同的返回结果。
注意"some_key"这个参数,singleflight
使用这个 key 去区分不同的请求,只有在相同的 key 的访问中,才会合并请求。
伪代码示例
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)
}
if c, ok := g.m[key]; ok {
g.mu.Unlock()
c.wg.Wait()
return c.val, c.err
}
c := new(call)
c.wg.Add(1)
g.m[key] = c
g.mu.Unlock()
c.val, c.err = fn()
c.wg.Done()
g.mu.Lock()
delete(g.m, key)
g.mu.Unlock()
return c.val, c.err
}
以上伪代码中,Group是Singleflight的主要结构,它有一个锁和一个map,用于存储所有的请求(call)。锁保证了对同一资源的访问在同一时间只能由一个进程进行。
Do方法是实现请求合并的核心,它首先会检查当前的请求(key表示的请求)是否正在被处理,如果是则等待处理结束,然后返回结果,如果不是则执行请求(fn),并将结果存储在call结构中,供之后的请求使用。
END