缓存预热应在系统启动或低峰期通过异步任务(如goroutine或任务队列)执行,避免阻塞http请求;需结合业务语义识别真实热点数据,复用线上数据访问逻辑写入redis,并加随机ttl防雪崩。

热点数据预热不能靠定时全量刷,得按业务节奏主动触发 + 按需加载,否则 Redis 里塞一堆冷数据反而拖慢响应、浪费内存。
预热入口该放在哪里:HTTP handler 还是独立 goroutine?
别在 http.HandlerFunc 里直接调用预热逻辑——它会阻塞请求,用户等得慌,还可能超时。预热本质是后台动作,和用户请求生命周期无关。
- 用
go func() { ... }()启动独立 goroutine,但要加简单错误日志兜底,避免 panic 静默失败 - 更稳妥的做法是接入任务队列(如
asynq或machinery),把预热请求转成异步任务,支持重试和延迟执行 - 如果只是小规模服务,可启动一个常驻
time.Ticker定期检查预热标记(比如 Redis 里一个hot:preload:flag的 string 值为"1"),有标记再执行,执行完清空
怎么判断哪些数据算“热点”:不能只看访问频次
单纯统计 GET 次数会误伤——比如某个接口被爬虫扫了 10 万次,但它返回的是错误页,缓存它毫无意义。得结合业务语义筛选。
每小时自动在推特搜索中国、加密货币、国际热点、美国热点、特朗普等话题的热度信息,提取前十热点,依据 X 平台真实算法权重(开源代码数据)为每个热点生成高曝光推文或线程。用户提及“推特热点”“Twitter热点”“推特搜索”“热点推文”“生成推文”“社交媒体监控”“Twitter监控”等关键词时触发。
- 优先从核心读接口的参数中提取标识:比如商品详情页的
product_id、订单列表的user_id + status组合 - 用 Redis 的
PFADD hot:sketch做 HyperLogLog 去重计数,比INCR更省内存;再配合ZINCRBY hot:scores累加权重(成功返回非空数据才加分) - 设置滑动窗口:用
TS.CREATE(RedisTimeSeries)或自建 sorted set +ZREMRANGEBYSCORE清理过期分数,只保留最近 5 分钟高分 key
预热时怎么写入 Redis:避免击穿、穿透、雪崩三连击
直接 SET 旧值不顶用——如果下游 DB 已更新但缓存没同步,预热进去的就是脏数据。必须走和线上一致的加载路径。
- 复用已有 data access 层的
GetProductByID(ctx, id)方法,而不是拼 SQL 或直连 DB;确保事务、缓存策略、降级逻辑完全一致 - 对每个 key 加随机 TTL(比如基础 TTL 3600s ± 300s),防止大量 key 同时过期引发雪崩
- 预热前先
EXISTS检查目标 key 是否已存在且未过期,存在就跳过——避免无谓覆盖和锁竞争 - 批量写入用
PIPELINE,但单次不超过 100 条;太多容易触发 Redis 内存淘汰或阻塞其他命令
如何验证预热是否生效:别只盯 Redis 的 KEYS
KEYS hot:* 只能看数量,看不出质量。真正关键的是缓存命中率是否提升、DB 查询量是否下降。
- 在预热逻辑里埋点:记录本次加载了几个 key、多少成功、平均耗时,打到日志或 Prometheus
preload_success_total{type="product"} - 对比预热前后 5 分钟的 Redis
INFO commandstats中cmdstat_get.hits和cmdstat_get.misses变化 - 用
redis-cli --scan --pattern "hot:*" | xargs redis-cli ttl抽样检查 TTL 分布,确认是否真有随机性
最麻烦的不是写代码,而是确定“什么时候该预热”——这往往得和产品、运营对齐活动排期,把预热指令变成可配置的开关,而不是硬编码在代码里。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










