事情本身不复杂,线索都在日志里。商品详情接口在高峰期数据库 CPU 冲到九成,Redis 命中率只有六成,日志里大量不存在的商品 ID 查询,来源是同一个 IP 循环随机数。
第一反应是「接口没有单 IP 限流,同一个来源可以无限请求」,验证下来不成立。
排查方向其实有限,先把可能性排一排。查询结果为空时没有写缓存,每次请求都落到库。另一种情况是入口没做参数格式与范围校验,非法 ID 也照查。
不容易想到的是,没有布隆过滤器,无法在入口提前拦掉不存在的键。
动手时先统计命中率与空结果请求的占比
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses'
空结果也写短缓存挡住重复请求
redis-cli set product:null:889912 '' EX 60
入口加参数校验与单 IP 限流
curl -s -o /dev/null -w '%{http_code}\n' 'https://api.example.com/product?id=abc'
剩下的就是用布隆过滤器做一层粗筛
redis-cli bf.reserve bf:product 0.01 10000000
恢复的判定其实很直接。空结果请求在缓存层就被拦下,数据库 QPS 回落到正常水平,命中率回到九成以上,接口 P99 稳在三十毫秒。
补一句。空值缓存要配短过期,否则真数据写进来还会读到空;布隆过滤器有误判但不会漏判,放在最前面做粗筛最合适。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
