CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Redis 缓存入门/课时/测试与监控
RawBlame
课时目录12 节

Redis 缓存入门

  1. 01Redis 是什么
  2. 02CLI 与键命名
  3. 03String 与计数
  4. 04Hash / List / Set / ZSet
  5. 05过期与淘汰
  6. 06缓存模式
  7. 07Spring Data Redis
  8. 08会话与 Sa-Token
  9. 09Docker 运行 Redis
  10. 10Pub/Sub 入门
  11. 11测试与监控
  12. 12综合练习

测试与监控

redis-cli INFO、集成测试 mock。

25 分钟

监控与测试:让 Redis 可观测、可验证

这一课你将能做到

  1. 用 INFO memory/stats/server 三段输出回答「Redis 健康吗」,并动手算出缓存命中率
  2. 用 SLOWLOG 抓慢命令,说清为什么生产绝不能开 MONITOR
  3. 用 Testcontainers 在集成测试里起真 Redis(含 @DynamicPropertySource 接线本站开关),并用 Boot 3.5 的 @MockitoBean 单测 miss 分支

为什么要学

前面 10 课你已经在「会用」,但工程闭环还差两件事:

  • 可观测:缓存生效了吗?命中率高不高?内存涨没涨?谁在执行慢命令拖累大家?——上生产前必须会看
  • 可验证:缓存代码怎么测?本站 CI 环境没有 Redis 服务,Testcontainers 让测试自己拉起一个真 Redis,测完即弃

这一课把两件事一次补齐,也是第 12 课综合实战的「验收工具包」。

先建立图像

INFO 分段(记三段就够)
 ├─ server  :版本、运行天数 —— 排查兼容问题
 ├─ memory  :used_memory_human、maxmemory_human、mem_fragmentation_ratio
 └─ stats   :keyspace_hits / keyspace_misses → 命中率;evicted_keys → 淘汰发生

命中率 = hits / (hits + misses)
SLOWLOG:服务端记录的慢命令黑名单(默认 >10ms 记录,保留 128 条)
MONITOR:实时打印所有命令——调试神器,生产毒药

跟着做

步骤 1:读 INFO 三段并算命中率

docker exec -it redis-dev redis-cli -a devpass123

INFO server   # redis_version、uptime_in_days
INFO memory   # used_memory_human、maxmemory_human(0=不限)、mem_fragmentation_ratio(1.0~1.5 健康)
INFO stats    # keyspace_hits、keyspace_misses、evicted_keys、total_commands_processed

SET hit:demo 1
GET hit:demo          # 命中 +1
GET hit:not-exist     # miss +1
INFO stats | grep -E "keyspace_(hits|misses)"   # 两个数字各涨 1

命中率公式:hits / (hits + misses)。业务缓存的合理预期通常在 80%~95%。

步骤 2:制造并抓一条慢命令

# 用 redis-benchmark 快速生成几万个随机 key(比 shell 循环快得多)
docker exec redis-dev redis-benchmark -n 50000 -t set -r 100000 -c 10 -q

# 慢日志阈值调低到 1ms 便于复现(单位微秒)
CONFIG SET slowlog-log-slower-than 1000
KEYS "key:*"          # 生产禁令!本步仅实验
SLOWLOG GET 5         # 能看到 KEYS 那一条:耗时、命令原文
SLOWLOG RESET
CONFIG SET slowlog-log-slower-than 10000   # 恢复默认 10ms

SLOWLOG 输出四元组:序号、时间戳、耗时(微秒)、命令原文。

步骤 3:认清 MONITOR 的危险

MONITOR    # 实时打印每一条命令——本机看看可以,Ctrl+C 退出

它让 Redis 额外做全量命令的格式化和分发,生产开启 = 主动给自己加压,流量大时直接拖垮。线上排查用 CLIENT LIST 和 SLOWLOG,别开 MONITOR。

步骤 4:Testcontainers 集成测试(真 Redis)

backend 测试目录新建 RedisIntegrationTest(如缺依赖,先在 pom 加 ,test scope):

org.testcontainers:junit-jupiter
@SpringBootTest
@Testcontainers
class RedisIntegrationTest {

    @Container
    static GenericContainer<?> redis =
        new GenericContainer<>("redis:7-alpine").withExposedPorts(6379);

    @DynamicPropertySource
    static void redisProps(DynamicPropertyRegistry registry) {
        registry.add("spring.data.redis.host", redis::getHost);
        registry.add("spring.data.redis.port", () -> redis.getMappedPort(6379));
        registry.add("codeforge.redis.enabled", () -> "true");   // 打开本站开关
    }

    @Autowired StringRedisTemplate redis;

    @Test
    void setAndGetWithTtl() {
        redis.opsForValue().set("test:key", "v", Duration.ofSeconds(60));
        assertThat(redis.opsForValue().get("test:key")).isEqualTo("v");
        assertThat(redis.getExpire("test:key")).isPositive();
    }
}

要点:容器端口是随机映射的,必须用 getMappedPort 动态注入;codeforge.redis.enabled=true 让 RedisConfig 的 4 个 Bean 真正装配。CI 不需要预装 Redis。

步骤 5:@MockitoBean 单测业务分支

不起容器的场景,Mock 掉模板测逻辑分支(Boot 3.5.4 用 @MockitoBean,@MockBean 已废弃):

@ExtendWith(SpringExtension.class)
class TrackCacheServiceTest {

    @MockitoBean
    StringRedisTemplate redisTemplate;

    @MockitoBean
    ValueOperations<String, String> valueOps;

    @Test
    void missThenFallbackToDb() {
        given(redisTemplate.opsForValue()).willReturn(valueOps);
        given(valueOps.get("coderoadmap:tracks:list")).willReturn(null);  // miss

        // 调用你的缓存服务 → 断言走到了 MySQL 回源分支(Mockito verify)
    }
}

分工原则:分支逻辑用 Mock 单测(快),真实读写用 Testcontainers 集成测(准)。

讲清楚要点

  1. 命中率是缓存的体检指标:正常业务缓存应 >80%;偏低先查 TTL 设置和 key 设计,而不是急着加缓存。
  2. evicted_keys > 0 说明内存上限触发过淘汰:缓存实例正常现象,持续增长要扩容;会话实例出现就是事故信号(用户被踢)。
  3. mem_fragmentation_ratio:>1.5 碎片偏多(大量增删后常见),activedefrag 或择机重启可缓解。
  4. SLOWLOG 是服务端视角的慢命令史:比客户端超时日志更准;抓到 KEYS、大集合的 HGETALL/SMEMBERS 就是优化目标。
  5. 测试金字塔落在 Redis 上:单测 Mock(分支)→ 集成 Testcontainers(真实协议)→ 生产 INFO/SLOWLOG(真实流量)。

你可能会懵的地方

  • 命中率多少算合格? 无绝对值。读多写少的内容站 90%+ 常见;刚上线冷启动期低是正常的,看趋势不看瞬时值。

  • Testcontainers 每次测试都拉镜像很慢? 首次拉取后镜像本地复用;容器随测试上下文启停,比「共享开发 Redis」干净且无状态污染。

  • @MockBean 不是还能用吗? Spring Boot 3.4 起废弃,3.5.4 用 @MockitoBean(org.springframework.test.context.bean.override.mockito 包)。老教程代码要迁移。

  • INFO stats 的 hits 会重复计吗? EXPIRE 过期导致的 miss 也计入 misses;命中率是业务视角的近似指标,关注趋势。

  • SLOWLOG 会不会把 Redis 拖慢? 记录本身开销极小(超时判断 + 环形缓冲),放心常开。

错法对照

错法问题正解
生产开 MONITOR 排查自我拖垮CLIENT LIST / SLOWLOG
只看接口快慢不看命中率缓存形同虚设不知情INFO stats 定期观测
测试直连开发机 Redis数据污染、CI 不可复现Testcontainers 隔离实例
用 @MockBean(Boot 3.5)已废弃编译告警@MockitoBean
集成测试写死端口 6379容器是随机映射getMappedPort + @DynamicPropertySource
SLOWLOG 阈值从不调抓不到也看不懂慢命令按环境调 slowlog-log-slower-than

卡点急救

  1. Testcontainers 起不来(Docker 没运行):先启动 Docker Desktop;CI 里确认 Runner 有 Docker 环境。
  2. @DynamicPropertySource 注入后 Bean 还是没装配:检查 codeforge.redis.enabled 是否给了字符串 "true"。
  3. SLOWLOG GET 空:没有超过阈值的命令。调低 slowlog-log-slower-than 再造慢命令。
  4. INFO 里 maxmemory 是 0:未设上限。容器/生产必设 maxmemory + 淘汰策略(第 9 课)。
  5. 测试里 opsForValue() 返回 null NPE:Mock 没配 given(redisTemplate.opsForValue()).willReturn(valueOps)。

面试常问

  • 怎么评估缓存效果? INFO stats 算命中率 hits/(hits+misses),看 evicted_keys 判断内存压力;结合接口 P99 与 MySQL QPS 改造前后对比。

  • 线上 Redis 突然变慢怎么排查? SLOWLOG 找慢命令 → redis-cli --bigkeys 找大 key → INFO memory 看碎片率 → 排查 KEYS 类命令或持久化抖动。

  • 你们的 Redis 相关代码怎么测? 两层:业务分支用 @MockitoBean(Boot 3.5)Mock 模板;集成用 Testcontainers 起真 Redis + @DynamicPropertySource 注入连接与本站开关,CI 可复现、无状态污染。

自测三问

  1. 命中率怎么算?evicted_keys 持续增长分别对缓存实例和会话实例意味着什么?
  2. 为什么生产禁开 MONITOR?替代手段是什么?
  3. Testcontainers 方案里必须动态注入的三个属性是什么?

小结一句话

INFO 看健康、SLOWLOG 抓慢、MONITOR 生产禁;测试用 Testcontainers 起真 Redis、@MockitoBean 测分支。

延伸

  • SLOWLOG 命令
  • 下一课:综合实战——给本站 TrackService 完整加上 Redis 缓存层,把 12 课所学串成一次真实交付。
加载本节练习…
← 上一课Pub/Sub 入门下一课 →综合练习