登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go singleflight:热点缓存失效时只让一个请求回源

来源:Golang学习网专题原创

时间:2026-06-08 19:06:00 588浏览 收藏

缓存击穿最危险的地方在于“同一瞬间”。一个热点 key 过期后,大量请求同时发现缓存未命中,并一起打到数据库。singleflight 的目标不是缓存数据,而是合并同 key 的回源动作。

singleflight 解决什么

它保证同一个 key 在同一时刻只有一个函数执行,其它请求等待结果。执行完成后,所有等待者共享同一份返回值。

不要把 key 设计得太粗

key 太粗会把不相关请求串行化,key 太细又无法合并热点。通常应使用业务对象 ID、租户 ID 和影响结果的参数共同组成 key。

错误和超时也要处理

如果回源失败,等待者会一起拿到错误。对于高价值热点,可以结合短 TTL 空值缓存、降级数据或后台刷新来减少反复击穿。

生产场景

适用于热点商品、热门文章、活动配置、权限列表等缓存失效后会集中回源的读路径。singleflight 重点解决瞬时并发合并,而不是替代缓存。

关键指标

  • singleflight shared 比例
  • 热点 key 回源次数与数据库 QPS
  • 回源失败后的等待者错误数量

常见误区

  • key 设计太粗导致不同请求互相阻塞
  • 回源函数无超时,所有等待者一起被拖住
  • 把错误结果长期缓存导致恢复后仍返回旧错误

落地建议

生产落地常和短 TTL 缓存、空值缓存、后台刷新一起使用。对高价值热点可以设置 stale-while-revalidate,让用户优先拿到可接受的旧值,同时后台异步刷新。

代码示例

var group singleflight.Group

func LoadProduct(ctx context.Context, id int64) (*Product, error) {
    key := fmt.Sprintf("product:%d", id)
    v, err, _ := group.Do(key, func() (any, error) {
        return repo.LoadProduct(ctx, id)
    })
    if err != nil {
        return nil, err
    }
    return v.(*Product), nil
}

上线检查

  • singleflight key 包含影响结果的参数。
  • 回源函数必须有 timeout。
  • 监控 shared 命中比例和回源错误。
声明:本文转载于:Golang学习网专题原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>