Kratos框架不内置缓存穿透/雪崩防护,需业务层显式实现:查不到的key须写空值标记(如"__NULL__")并设短TTL(60~300秒),读取时先校验空标记,避免DB暴露;关键ID应在middleware层前置校验格式。

Kratos 框架本身不内置缓存穿透/雪崩防护逻辑,所有防御必须由业务层显式实现 —— 它只提供 cache、redis、middleware 等基础能力,具体策略得你亲手加。
缓存穿透:查不到的 key 不能放行到 DB
在 Kratos 中,穿透问题不会自动消失。比如你用 redis.Get(ctx, key) 拿不到值,就直接调 dao.GetUserByID(ctx, id),而 DAO 层查不到又不写缓存,攻击者拿一堆 id=-1 或随机 UUID 轮询,DB 就会暴露。
- 必须在业务 handler 或 service 层判断:DB 返回
nil时,主动写入一个空标记,例如redis.SetEX(ctx, key, "__NULL__", time.Second*60) - 读取时先检查是否等于
"__NULL__"字符串,是则直接返回nil,避免反序列化失败 - 不要用太长 TTL(如 24h),60~300 秒足够防短时扫描;过长会导致真实数据上线后无法及时生效
- 若 key 有明确格式(如正整数 ID),可在 middleware 层提前校验:
if id ,从入口拦住一部分
缓存雪崩:别让大批 key 同一时刻过期
Kratos 的 redis client(如 github.com/go-redis/redis/v9)默认不干预过期时间设置,如果你统一写 redis.SetEX(ctx, key, val, time.Hour),所有商品、用户、配置缓存都按整点失效,流量高峰一来,DB 就被压穿。
- 给 TTL 加随机偏移:比如基础 3600 秒,再加
rand.Int63n(300)(±5 分钟),变成time.Second * (3600 + rand.Int63n(300)) - 避免在定时任务或初始化里批量设相同过期时间;如果必须批量预热,每个 key 的
ExpireAt应错开至少 10 秒 - 对真正不能失效的热点数据(如系统开关、降级开关),可设为永不过期(
redis.Set(ctx, key, val, 0)),靠主动更新而非被动过期 - Kratos 的
conf配置加载不涉及缓存过期,但如果你把配置也塞进 Redis 并设固定 TTL,同样要加随机
为什么 Kratos 不帮你做这些?
因为穿透和雪崩的应对高度依赖业务语义:
- 哪些 key 可以缓存空值?哪些空值代表恶意(如非法 token)而该限流?Kratos 不知道
- 哪些数据能加随机 TTL?订单号缓存加了随机,下游对账服务可能因“看到不同过期时间”产生困惑
- 布隆过滤器该建多大?误判率容忍多少?这些参数必须你根据数据量和 QPS 来算,框架没法猜
- 你用的是 Redis Cluster 还是单节点?是否启用了 Redis 的
maxmemory-policy?这些都会影响雪崩表现,Kratos 不做假设
最易被忽略的一点:Kratos 的 transport/http middleware 可以统一加请求 ID 和日志,但**它不会自动记录「缓存 Miss 且 DB 为空」的日志** —— 如果你不手动打点,根本发现不了穿透正在发生。


















