Redis

2 阅读9分钟

Redis 是后端面试中的“重头戏”,因为它不仅考察你对数据结构的理解,还考察你对高并发、分布式架构以及底层原理的掌握。

结合最新的面试趋势和搜索到的资料,我为你整理了 Redis 最常考的 5 大核心模块,涵盖了从基础到进阶的必问问题。

1. 基础与数据结构(必问)

这部分通常作为开场,考察你是否真的用过 Redis,而不仅仅是把它当做一个简单的 KV 存储。

  • Redis 为什么这么快?
    这是最经典的问题。你需要从以下 4 个维度回答:

    1. 纯内存操作:数据存储在内存中,读写速度是纳秒级,没有磁盘 I/O 瓶颈。
    2. 单线程模型(核心):避免了多线程频繁的上下文切换和锁竞争(注意:Redis 6.0 引入了多线程处理网络 I/O,但命令执行依然是单线程)。
    3. 高效的数据结构:底层使用了跳表、哈希表等高效结构,时间复杂度多为 O(1) 或 O(logN)。
    4. I/O 多路复用:使用 epoll 机制,单线程能高效处理大量并发连接。
  • Redis 有哪些核心数据类型?应用场景是什么?
    不要只背名字,要结合场景说:

    • String(字符串) :缓存、计数器(INCR)、分布式锁。
    • Hash(哈希) :存储对象(如用户信息、商品详情)。
    • List(列表) :消息队列(LPUSH + RPOP)、最新文章列表。
    • Set(集合) :去重(如标签)、共同好友(求交集 SINTER)。
    • ZSet(有序集合) :排行榜(带分数排序)、带权重的队列。

2. 缓存“三剑客”:穿透、击穿、雪崩(高频)

这是面试中出现率最高的考点,考察你处理高并发异常的能力。

问题现象与原因解决方案
缓存穿透查询不存在的数据,请求直达数据库。恶意攻击可导致 DB 崩溃。1. 缓存空对象(设置短 TTL)。 2. 布隆过滤器(拦截无效 Key)。
缓存击穿热点 Key 突然过期,大量并发瞬间击穿缓存访问 DB。1. 互斥锁(分布式锁),只让一个线程重建缓存。 2. 热点数据永不过期(逻辑过期)。
缓存雪崩大量 Key 同时过期,或 Redis 宕机,导致流量全部涌向 DB。1. Key 的过期时间设为随机值。 2. 构建 Redis 高可用集群(哨兵/Cluster)。 3. 限流降级。

3. 数据一致性与持久化(进阶)

考察你在生产环境中如何保证数据不丢、不错。

  • 如何保证 Redis 与数据库(MySQL)的数据一致性?
    这是一个开放性问题,没有完美方案,通常回答:

    • 常用策略先更新数据库,再删除缓存(Cache Aside 模式)。
    • 延时双删:先删缓存 -> 更新数据库 -> 延时(如 500ms)再次删缓存(防止并发脏数据)。
    • 监听 Binlog:使用 Canal 监听 MySQL 的 Binlog,异步删除或更新 Redis,保证最终一致性。
  • Redis 的持久化机制(RDB vs AOF)?

    • RDB (快照) :定时将内存数据 dump 到磁盘。优点是文件小、恢复快;缺点是可能丢失最后一次快照的数据。
    • AOF (日志) :记录每次写操作。优点是数据更安全(秒级同步);缺点是文件大、恢复慢。
    • 生产建议:通常混合使用,或者只用 AOF(appendfsync everysec),兼顾性能与安全。

4. 分布式锁(实战)

  • 如何用 Redis 实现分布式锁?

    • 核心命令SET key value NX EX seconds(原子性操作:不存在则设置,并设置过期时间)。

    • 关键点

      1. 互斥性:利用 NX 保证只有一个客户端能设置成功。
      2. 防死锁:必须设置过期时间(TTL)。
      3. 防误删:解锁时比对 Value(通常用 UUID),防止删错别人的锁(配合 Lua 脚本保证原子性)。
      4. 看门狗(Redisson):后台线程自动给锁续期,防止业务没执行完锁就过期了。

5. 架构与底层原理(加分项)

  • Redis 是单线程的,为什么还能支持高并发?
    除了前面提到的内存和 I/O 多路复用,还可以补充:Redis 6.0 引入了多线程处理网络数据的读写和协议解析,但命令执行阶段依然是单线程,所以不需要考虑锁竞争。

  • Redis 的过期键删除策略?

    • 惰性删除:访问 Key 时才检查是否过期,过期则删除(节省 CPU,但浪费内存)。
    • 定期删除:每隔一段时间随机抽取一批 Key 检查(平衡 CPU 和内存)。
    • 内存淘汰策略:当内存满了,根据策略(如 LRU、LFU)主动踢掉旧数据。
  • Redis 集群方案(主从、哨兵、Cluster)?

    • 主从复制:数据备份。
    • 哨兵模式 (Sentinel) :监控主节点,主节点挂了自动选举新主,实现高可用
    • Cluster 模式:官方提供的分布式方案,数据分片(16384 个槽),实现高可用 + 高并发(水平扩展)

测开

作为测试开发工程师(测开),面试官考察 Redis 的角度与后端开发有所不同。开发更关注底层原理和架构实现,而测开更关注“怎么测”、“怎么验证”以及“如何利用 Redis 辅助测试”

结合你之前的提问和搜索到的资料,我为你总结了测开面试中 Redis 的高频考点,主要分为以下四个维度:

1. 核心考点:Redis 的测试策略(怎么测?)

这是测开面试中最具区分度的部分,面试官想知道你是否有针对缓存系统的测试思维。

  • 功能测试点:

    • 数据一致性:这是重中之重。如何验证 MySQL 和 Redis 的数据是否一致?(例如:更新 DB 后,是否校验了缓存的删除或更新?)
    • 过期策略:设置 Key 的 TTL,验证它是否按时过期;验证过期后再次访问是否回源查库。
    • 持久化验证:重启 Redis 服务,验证 RDB 或 AOF 是否生效,数据是否丢失。
    • 权限与安全:验证配置密码后,无密码访问是否被拒绝;验证敏感数据是否加密存储。
  • 异常与容错测试:

    • 内存满时的表现:配置 maxmemory,验证达到上限时,淘汰策略(如 LRU)是否按预期工作,是否会报错。
    • 主从切换:模拟主节点宕机,验证哨兵(Sentinel)是否能自动选举新主,从节点是否接管服务,业务是否中断。
    • 网络异常:模拟网络延迟或中断,验证客户端的重连机制和超时处理。
  • 经典场景测试(三剑客):

    • 缓存穿透:构造数据库中不存在的 Key 进行大量请求,验证系统是否崩溃,布隆过滤器或空值缓存是否生效。
    • 缓存雪崩:模拟大量 Key 同时过期或 Redis 宕机,验证系统是否有降级或限流措施。
    • 缓存击穿:模拟热点 Key 在过期瞬间的高并发访问,验证互斥锁是否生效。

2. 工具与实战:如何模拟与压测?

测开需要掌握工具来模拟上述场景。

  • 性能压测工具:

    • redis-benchmark:官方自带工具。面试官可能会问:“如何模拟 100 个并发连接,发送 10 万次 SET 请求?”(命令:redis-benchmark -c 100 -n 100000 -t set)。
    • JMeter:如何配置 Redis 插件进行压力测试,如何监控 QPS 和响应时间。
  • 脚本能力(Python/Shell):

    • 可能会让你手写简单的脚本(使用 redis-py 库)来构造测试数据,或者验证数据一致性。
    • 例如:写一个脚本,循环写入 1000 条数据,然后读取验证,最后清理数据。
  • 监控与指标:

    • 如何查看 Redis 的命中率?(使用 info stats 查看 keyspace_hitskeyspace_misses)。
    • 如何监控慢查询?(使用 SLOWLOG 命令)。

3. 业务场景:测开如何利用 Redis?

测开不仅仅是测 Redis,还要利用 Redis 来提升测试效率。

  • 测试数据构造:利用 Redis 的高速读写特性,在测试前预热数据,或者在测试中通过 Redis 共享状态(例如在分布式测试中,通过 Redis 记录已执行的测试用例 ID,避免重复执行)。
  • 分布式锁测试:如果你的项目涉及定时任务或多机部署,测开需要验证 Redis 分布式锁是否有效防止了任务的重复执行。
  • 计数器验证:验证点赞、浏览量等计数器功能,使用 INCR 命令是否准确,并发下是否会少计。

4. 基础理论:必须掌握的“八股文”

虽然是测开,但基础原理不懂就无法设计深层用例。

  • 数据结构:String(缓存/计数)、List(消息队列)、Set(去重/抽奖)、ZSet(排行榜)。你需要知道针对每种结构该测什么(例如 ZSet 要测分数排序是否正确)。
  • 持久化:RDB(快照)和 AOF(日志)的区别。测试时要注意:RDB 可能会丢数据,AOF 文件过大恢复慢。
  • 双写一致性:先删缓存还是先更新数据库?(通常是先更库再删缓)。测开需要设计并发用例来验证这个逻辑是否存在竞态条件。

💡 测开面试回答话术示例

面试官: “你怎么测试 Redis 的缓存穿透?”

你的回答(测开版):

“针对缓存穿透,我会从场景模拟验证指标两个方面入手:

  1. 场景构造:我会写一个 Python 脚本或使用 JMeter,构造一批数据库中绝对不存在的 ID(比如负数或随机字符串),然后模拟高并发(比如 500 QPS)持续请求查询接口。

  2. 验证手段

    • 看日志:观察后端日志,看是否有大量的 SQL 查询请求打到数据库。
    • 看监控:检查数据库的 CPU 和负载是否飙升。
    • 看 Redis:检查 Redis 中是否存入了空值(如果我们采用了缓存空对象的策略)。
  3. 预期结果:如果配置了布隆过滤器,请求应该在到达 Redis 之前就被拦截;如果配置了缓存空值,Redis 中应该有对应的空 Key,且数据库压力在可控范围内。”

总结: 测开面试 Redis, “怎么测”比“是什么”更重要。重点展示你对数据一致性、高并发异常场景、以及自动化测试工具的掌握。