为了研究Redis 三大守护神,我做了一个本地模拟!
2026/9/24 12:29:39 网站建设 项目流程

Kill-redis-plan

本地模拟缓存击穿、缓存穿透、缓存雪崩,用于研究redis缓存

开源网站自行🔍

本地复现 Redis 缓存穿透、击穿、雪崩。

注意力在缓存层:Compose 只跑 Redis,存储用进程内 FakeDB,用 Go goroutine 打并发。

观测挂在内核上:每秒输出一个生产指标窗口,结束后汇总全程指标,由人根据关联变化判断缓存状态。

  • 穿透penetrate查不存在的数据。缓存一直空,每次请求都打到存储。
  • 击穿breakdown单个热点 key 过期,大量并发同时 miss,瞬间打到存储。
  • 雪崩avalanche大批量 key 同一时刻过期,大面积 miss,存储被打满。

reports日志 观测格式

avalancheconcurrency=2000planned=2400qps=400duration=6skeys=200expiry=2s backendredis=127.0.0.1:6379db_latency=100msdb_concurrency=20refill_ttl=30stimedonerequest_total request_p99 request_errors redis_hit redis_miss redis_hit_rate redis_miss_rate redis_expired redis_errors origin_total origin_unique_keys origin_breadth origin_hot_share db_total db_saturation db_max_waiting db_wait_p99 db_found db_not_found 1s400/24004001.553ms03990100.0%0.0%00000.0%0.0%00.0%00s002s794/24003991.082ms0395598.8%1.2%6055100.0%20.0%50.0%00s003s1143/2400401506.879ms016523541.2%58.8%194023519583.0%0.9%19896.2%100455.679ms18304s1600/2400400556.031ms04000100.0%0.0%00000.0%0.0%3719.4%0157.456ms5705s1999/2400399992µs04000100.0%0.0%00000.0%0.0%00.0%00s006s2400/24004001.109ms04000100.0%0.0%00000.0%0.0%00.0%00s00resultstatus=okelapsed=6.001sdone=2400/2400failures=0requesttotal=2400errors=0input_rejected=0p99=505.855msoverflow=0redishit=2160miss=240hit_rate=90.00%errors=0ops_p99=1.074msoverflow=0expired=200evicted=0origintotal=240unique_keys=200duplicate_reads=40valid_rate=100.00% hot_keykey=item:155total=2share=0.83%max_inflight=2dbtotal=240found=240not_found=0errors=0max_waiting=100wait_p99=455.679mswait_overflow=0query_p99=101.055msquery_overflow=0

具体还是可以到项目中去观察,最好来到本地跑一下,观测一下数值在面对 三大问题的变化。

数据流

一次请求:cache.Get(id)→ RedisGET

hit 则返回,FakeDB 不动。

miss 则store.Get(占槽、睡延迟、查 map)。

有值就 RedisSET带 TTL 再返回;没值只返回空,不写 Redis。

回源

回源=Redis Miss ->向 DB 发起查询(不管 Found 还是 Not Found)

回源是个动作

  • Found:一次有效回源
  • Not Found:一次无效回源

回源率 =origin_total/redis_miss

回源集中度 =origin_hot_key_total/origin_total

穿透penetrate

Redis 返回 nil ->回源查询 DB ->DB 返回结果为空 / 影响行数为0->缓存穿透

捕获一次就是一次穿透

穿透次数 =origin_totalDB Not Found

观测:Server / 全链路监控层 中加入Redis Miss+DB Not Found的复合判定埋点.

  • 恶意攻击:攻击者构造大量不存在的 ID(如负数 ID、随机字符串)频繁请求接口

  • 业务 bug:前端传入了错误的参数,如删除了某条数据后仍然不断查询

  • 爬虫扫描:遍历式爬虫尝试访问不存在的资源

  • -t unique:默认。下标 i(从 0 起)打 id1000000+i,每个 ID 只请求一次,模拟不断生成新 ID 的随机扫描。

  • -t repeat:从一组不存在 ID 中均匀抽取并打散后齐发,模拟失效链接、爬虫或攻击脚本同时反复访问一批不存在资源。默认id_pool=100;当-n较小时自动缩小池子,确保会产生重复请求。

两个模式都会齐发。开启方案 2 后,repeat的首波仍可能在空值写入前并发回源;只有首波结束后的后续请求,才会命中短 TTL 空值缓存。

Q&A 为什么没有用redis_miss?

防击穿组件(SingleFlight / 互斥锁)的拦截:

如果有 1000 个并发请求打过来,Redis 确实记录了 1000 次 Miss。
但如果应用层配置了 singleflight,只有 1 个请求真正去查了 DB,其余 999 个在内存里挂起等待复用。
此时:Redis Miss = 1000 != 真实回源数 = 1
如果拿 Redis Miss 当回源,你会误以为数据库正承受 1000 次冲击,但实际上数据库压力只有 1。

击穿breakdown

击穿 =针对同一 Key 的高并发回源(origin_hot_key_max_inflight)DB Found

origin_total=106origin_unique_keys=1origin_hot_key=item:1 origin_hot_key_total=106origin_hot_key_max_inflight=105origin_hot_key_total/origin_total(回源集中度)100% origin_hot_key_max_inflight>>1

针对同一 key 的高并发回源: 106 次回源全部针对 item:1,其中最多有 105 次同时进行。

热点 Key 过期/失效 ->大量并发请求同时 Redis Miss ->瞬间并发回源 DB ->DB 成功返回有效数据 ->缓存击穿

预热:
item:1写入 Redis(TTL 用 config 里的值),每 50ms 轮询EXISTS,直到 key 消失;
时限为ttl+3s,超时则失败退出。
然后-n个 goroutine 同时打 id1
回写完成前,其余请求也会 miss,叠到同一条回源上。

雪崩avalanche

雪崩特征 =大面积 Redis Miss多 Key 的有效回源DB 满载、排队与请求延迟上升

redis_expired=200redis_miss_rate=56.3% origin_total=224origin_unique_keys=200origin_breadth=89.3% origin_hot_share=0.9% db_found=180db_saturation=91.4% db_max_waiting=100db_wait_p99=453.375ms request_p99=503.295ms
  • 大面积 Redis Miss:200 个 key 同时过期,Redis Miss 率在该窗口升至 56.3%。、
  • 多 Key 的有效回源:224 次回源覆盖 200 个不同 key,广度为 89.3%;
  • 排除击穿与穿透db_found=180表示这些请求查到有效数据,不是缓存穿透。origin_hot_share=0.9%表示回源没有集中在单一热点 key,因此不是击穿。
  • DB 满载、排队与请求延迟上升:DB 在该窗口 91.4% 的时间处于满载,最多 100 个请求等待并发槽,DB 等待 P99 为 453.375ms,最终将请求 P99 推高到 503.295ms。
  • 预热:
    • 先用同一个绝对过期时间预热item:1..keys,随后立即启动固定 QPS 的持续流量:
    • 0..ttl:缓存正常命中。
    • key 集体过期后:多 key 同时 miss、回源,DB 开始满载和排队。
    • 回填完成后:Redis 命中恢复,DB 清空积压请求。

文章内容来自README,非AI编写以及润色!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询