长沙网站开发设计,网站建设需要些什么资料,中企动力常州分公司,网站备案有什么要求吗该项目原作者#xff1a;https://github.com/geektutu/7days-golang。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。
1 缓存雪崩、缓存击穿与缓存穿透
概念解析#xff1a;
缓存雪崩#xff1a;缓存在同一时刻全部失效#xff0c;造成瞬…该项目原作者https://github.com/geektutu/7days-golang。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。
1 缓存雪崩、缓存击穿与缓存穿透
概念解析
缓存雪崩缓存在同一时刻全部失效造成瞬时DB请求量大、压力骤增引起雪崩。缓存雪崩通常因为缓存服务器宕机、缓存的 key设置了相同的过期时间等引起。缓存击穿一个存在的key在缓存过期的一刻同时有大量的请求这些请求都会击穿到 DB 造成瞬时DB请求量大、压力骤增。缓存穿透查询一个不存在的数据因为不存在则不会写到缓存中所以每次都会去请求 DB如果瞬间流量过大穿透到 DB导致宕机。
2 singleflight介绍
singleflight 是一个非常有用的包它提供了一种机制来抑制对某个函数的多次重复调用。这个包特别适用于避免在高并发场景下对同一资源的重复请求比如在缓存击穿问题中多个请求同时访问同一个资源时singleflight 可以确保这些请求中只有一个实际执行其他请求则等待这个结果从而减少对后端服务的压力
核心概念 singleflight 包中定义了一个名为 Group 的结构体类型它表示一类工作并形成一个命名空间在这个命名空间中可以使用重复抑制来执行工作单元。当你调用 Do 方法时它接收一个键key和一个函数fn。这个键是用来标识请求的唯一性而函数则是实际要执行的操作。Do 方法首先会检查是否已经有相同的请求正在处理中。如果有那么当前请求就会被放入一个等待队列直到第一个请求完成并返回结果。这时所有等待的请求都会收到相同的结果。
使用场景 singleflight 常用于以下场景
缓存击穿在高并发的情况下某个热点数据缓存失效后大量的请求直接访问数据库造成数据库的压力过大甚至宕机的现象。使用singleflight 可以确保即使在缓存失效时也只有一次数据库请求被执行其他请求等待这次请求的结果 。避免重复计算在需要进行复杂计算且结果可以被多个请求共享的场景中singleflight 可以确保计算只执行一次其他请求共享这个结果从而提高效率。
基本使用 使用 singleflight 时首先需要创建一个 Group 实例然后通过调用 Do 方法来执行具体的函数。如果相同的键对应的函数已经 被调用那么后续的调用将会等待第一个调用的结果而不是重复执行函数
var g singleflight.Group// 模拟耗时操作
func getData(key string) (string, error) {// 模拟数据库查询耗时time.Sleep(2 * time.Second)return data for key, nil
}func main() {// 第一次调用result1, err, shared : g.Do(key, func() (interface{}, error) {return getData(key)})if err ! nil {log.Fatal(err)}fmt.Printf(Result1: %s, Shared: %v\n, result1, shared)// 第二次调用将共享第一次调用的结果result2, err, shared : g.Do(key, func() (interface{}, error) {return getData(key)})if err ! nil {log.Fatal(err)}fmt.Printf(Result2: %s, Shared: %v\n, result2, shared)
}在这个例子中即使 getData 函数被调用了两次但由于 singleflight 的机制实际的数据库查询操作只执行了一次两次调用共享了这个结果
3 运用singleflight到geecache中
type Group struct {name stringgetter GettermainCache cachepeers PeerPicker// use singleflight.Group to make sure that// each key is only fetched onceloader *singleflight.Group
}func NewGroup(name string, cacheBytes int64, getter Getter) *Group {// ...g : Group{// ...loader: singleflight.Group{},}return g
}func (g *Group) load(key string) (value ByteView, err error) {// each key is only fetched once (either locally or remotely)// regardless of the number of concurrent callers.viewi, err : g.loader.Do(key, func() (interface{}, error) {if g.peers ! nil {if peer, ok : g.peers.PickPeer(key); ok {if value, err g.getFromPeer(peer, key); err nil {return value, nil}log.Println([GeeCache] Failed to get from peer, err)}}return g.getLocally(key)})if err nil {return viewi.(ByteView), nil}return
}修改 geecache.go 中的 Group添加成员变量 loader并更新构建函数 NewGroup。修改 load 函数将原来的 load 的逻辑使用 g.loader.Do 包裹起来即可这样确保了并发场景下针对相同的 keyload 过程只会调用一次。