怎样在Golang中使用Redis实现防雪崩机制_利用Singleflight合并请求

云磊君_8070

云磊君_8070

2026-06-11

494人浏览

原创

直接并发查redis触发雪崩是因为大量请求同时发现缓存为空,穿透至后端批量重建,若未用singleflight合并请求且未兜底空值缓存,会导致数据库或接口瞬间过载。

怎样在golang中使用redis实现防雪崩机制_利用singleflight合并请求

为什么直接并发查Redis会触发雪崩

当大量请求同时发现缓存(GET user:123)为空,就会穿透到后端服务批量重建缓存。如果后端是数据库或HTTP接口,瞬间几百个相同 user:123 查询打过去,资源直接打满——这不是缓存没用,而是“空缓存没兜住 + 请求没合并”双重失效。

SingleFlight 不能直接包 Redis 的 Get 操作

singleflight.Group 的作用是:对相同 key 的多个并发调用,只让第一个真正执行函数,其余等待其返回结果。但它不感知 Redis 的语义,比如你传一个 redis.Client.Get(ctx, "user:123") 进去,它只会等这个 Get 完成,但不会帮你把 nil 结果写回 Redis,也不会自动加空值缓存防穿透。

常见错误写法:

// ❌ 错误:没处理 miss 场景,也没写缓存
v, err, _ := g.Do("user:123", func() (interface{}, error) {
    return rdb.Get(ctx, "user:123").Result()
})

正确做法必须显式判断 redis.Nil 并决定是否回源、是否写空值:

  • 先用 singleflight 合并所有对同一 key 的请求
  • 在 group 函数里调用 rdb.Get,若返回 redis.Nil,则调用回源函数(如 loadFromDB("user:123"))
  • 无论回源成功与否,都把结果(含空值)写入 Redis,并设 TTL
  • 注意:空值建议用 SET user:123 "" EX 60 而非 nil,否则下次 Get 还是 redis.Nil

如何避免 SingleFlight key 和 Redis key 不一致导致漏合并

典型坑:业务中 Redis key 是 "user:" + uid,但 singleflight.Do 传的是 "user_load_" + uid 或带参数哈希的字符串,结果看起来一样的请求被拆成多个 group,雪崩照旧。

Golang Naming
Golang Naming

Go(Golang)命名规范 — 包括包、构造函数、结构体、接口、常量、枚举、错误、布尔值、接收器、getter/setter、函数等。

下载

必须保证两者 key 完全一致:

  • 推荐统一用缓存 key 本身作为 singleflight 的 key,例如 "user:123"
  • 如果需区分读写场景(如更新时要 bypass group),再额外加前缀,但读场景保持纯净
  • 避免对 key 做无意义转换:比如 fmt.Sprintf("%s_%d", "user", uid) 和 "user:" + strconv.Itoa(uid) 表现可能不同(空格、符号),造成逻辑分裂

空值缓存 TTL 设置太短或太长都会出问题

写空值不是一劳永逸:SET user:123 "" EX 5 可能刚过期又来一波并发;设成 EX 3600 又会导致真实数据更新延迟暴露。

更稳妥的做法是分层控制:

  • 空值 TTL 设为「基础保护值」,比如 EX 60,足够挡住突发流量
  • 配合「逻辑过期」:实际存的 value 是 JSON,含 {"data":null,"expire_at":1717028400},应用层读取后自行判断是否需异步刷新
  • 或者用「布隆过滤器」前置拦截非法 key,从源头减少 redis.Nil 出现场景

SingleFlight 解决的是“同一合法 key 的并发击穿”,不是“海量非法 key 扫描”。后者得靠限流或过滤,别指望 group 拦得住。

golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

redis golang

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

499

5

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

596

5

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

1056

5

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.05

771

5

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.05.21

1546

6

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

4294

18

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

2025.06.10

1954

13

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

2025.06.17

3866

17

golang数组大全
golang数组大全

本专题整合了golang数组相关问题解决方法,想了解更多相关内容,请阅读下面的文章。

2025.06.20

4586

22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
phpEnv手册
phpEnv手册

共0课时 | 0人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.5万人学习