一、Redis 核心数据结构与底层实现

在回答 Redis面试必考50题 时,数据结构是绕不开的第一道关卡。面试官通常不会只问“Redis有哪些数据类型”,而是会深入询问底层编码(Encoding)以及为什么这样设计。

1.1 SDS(简单动态字符串)

Redis 不使用 C 语言的字符串,而是构建了 SDS (Simple Dynamic String)。相比 C 字符串,SDS 的优势在于:

  • 常数复杂度获取字符串长度:SDS 在 struct 中记录了 length 属性。
  • 杜绝缓冲区溢出
  • 减少修改字符串带来的内存重分配次数:通过空间预分配(lazy free)和惰性空间释放机制。
  • 二进制安全:API 不会截断字符串。

1.2 跳表 (Skip List) vs 红黑树

这是 Redis面试必考50题 中的高频陷阱题。Redis 的 ZSet 底层使用跳表而非红黑树,主要原因如下:

  1. 范围操作更友好:跳表可以更容易地进行范围查询(如 zrangebyscore),时间复杂度为 O(logN + n),而红黑树需要中序遍历。
  2. 实现更简单:跳表的插入删除操作比红黑树简单得多,且性能损耗极小。
  3. 缓存命中率:跳表是顺序访问内存,而红黑树是随机访问,跳表对 CPU 缓存更友好。
数据结构 底层编码 适用场景
String SDS 计数器、对象存储、分布式锁
List QuickList (ZipList + Node) 消息队列、最新列表
Hash ZipMap / HashTable 存储对象字段
Set IntSet / HT 点赞、共同好友
ZSet Ziplist / Skiplist + HT 排行榜、带权重的消息队列

二、持久化机制:RDB 与 AOF 的深度博弈

在 Redis面试必考50题 中,持久化方案的选择及其优缺点是必问内容。理解 RDB 和 AOF 的触发机制及合并过程至关重要。

2.1 RDB (Redis Database)

RDB 是数据快照,适合大规模数据恢复。触发方式包括:

# 手动触发
SAVE (阻塞主进程,生产环境禁用)
BGSAVE (fork子进程,推荐)

配置触发

save 900 1 save 300 10 save 60 10000

2.2 AOF (Append Only File)

AOF 记录写命令,数据更安全。重写(Rewrite)机制用于解决 AOF 文件过大问题。

  • 无追加模式 (no-appendfsync):不保证数据安全性,性能最高。
  • 每秒同步 (everysec):默认策略,平衡性能与数据丢失风险(最多丢失1秒数据)。
  • 每次同步 (always):数据安全性最高,但性能较差。

2.3 AOF 重写原理

当 AOF 文件体积超过设定阈值时,Redis 会 fork 一个子进程来生成新的 AOF 文件。子进程不读取旧文件,而是遍历内存中的数据集,将已存在的键重新序列化为命令写入新文件。同时,主进程将重写期间的新写命令记录到 aof_rewrite_buffer 中,重写完成后合并,确保数据一致性。

三、高可用架构:Sentinel 与 Cluster

随着数据量增长,单机 Redis 无法满足需求。在 Redis面试必考50题 中,集群方案的选择和原理是区分初级与高级工程师的关键。

Sentinel 核心功能

Sentinel 主要用于实现主从切换和通知。

  • 监控 (Monitoring):不断检查主服务器和从服务器是否正常工作。
  • 自动故障转移 (Automatic Failover):当主节点不可达时,将其中一个从节点提升为主节点。
  • 配置提供者 (Configuration Provider):客户端通过 Sentinel 获取当前主节点地址。

脑裂问题:网络分区导致主节点认为从节点离线,从节点提升为主,原主节点恢复后变为从节点,导致数据不一致。解决方案:配置 min-slaves-to-write 和 min-slaves-max-lag。

Cluster 分布式架构

Redis Cluster 是 Redis 官方推出的分布式解决方案,去中心化,无 Proxy 层。

  • 数据分片:使用 哈希槽 (Hash Slot)。共有 16384 个槽,数据分布在 3 个主节点上。
  • 路由请求:客户端发送命令时,先计算 key 的 hash 值对 16384 取模,确定槽位,再重定向到对应节点。
  • Gossip 协议:节点间通过 Gossip 协议交换元数据,保证集群状态最终一致。
# 客户端连接示例
redis-cli -c -h 127.0.0.1 -p 7000

四、高并发下的缓存难题与解决方案

这是 Redis面试必考50题 中结合实际业务场景最多的部分,面试官常问:“如果缓存挂了怎么办?”或:“如何保证缓存与数据库的一致性?”

① 缓存穿透

现象:查询不存在的数据,请求直达数据库。

解决方案:

  • 布隆过滤器 (Bloom Filter):预判 key 是否存在。
  • 缓存空对象:将查询结果为 null 的 key 也缓存,设置短过期时间。

② 缓存击穿

现象:热点 key 过期瞬间,大量请求涌入数据库。

解决方案:

  • 互斥锁 (Mutex Key):只允许一个线程查库并重建缓存,其他线程等待。
  • 逻辑过期:不设 TTL,在 value 中内置过期时间,后台异步重建缓存。

③ 缓存雪崩

现象:大量 key 同时过期,或 Redis 宕机。

解决方案:

  • 随机 TTL:给过期时间加上随机值,避免集体过期。
  • 高可用:使用 Sentinel 或 Cluster 防止单点故障。
  • 限流降级:使用 Hystrix 或 Sentinel 进行流量控制。

4.1 缓存与数据库一致性策略

在 Redis面试必考50题 中,双写一致性是难点。推荐策略:

  1. 先更新数据库,再删除缓存(Cache Aside Pattern):这是最常用的策略。虽然存在短暂不一致,但比先删缓存再更库更安全。
  2. 延时双删:先删缓存,更新数据库,再休眠一会儿删缓存。解决并发更新导致缓存残留问题。
  3. 订阅 Binlog 异步删除:通过 Canal 监听 MySQL Binlog,异步删除 Redis 缓存。解耦业务代码,保证最终一致性。

五、生产环境常见场景与最佳实践

除了理论,面试官还关注实际动手能力。以下是 Redis面试必考50题 中涉及的高频场景题。

5.1 分布式锁的实现

使用 SETNX key value EX seconds 实现分布式锁。但需考虑锁续期(看门狗机制)和原子性问题。推荐使用 Redisson 客户端,它内置了看门狗自动续期和可重入锁机制。

// Redisson 示例
RLock lock = redisson.getLock("myLock");
lock.lock();
try {
    // 业务逻辑
} finally {
    lock.unlock();
}

5.2 消息队列

Redis 的 LIST 结构可实现简单队列,PUB/SUB 实现发布订阅。但对于高吞吐、高可靠场景,建议使用 RocketMQ 或 Kafka。Redis 队列适合轻量级、非关键任务。

5.3 计数与排行榜

利用 ZSet 的 score 属性实现排行榜。例如,微博热搜榜,key 为微博 ID,score 为热度值。查询 Top 10 只需 ZREVRANGE key 0 9,效率极高。

六、总结

掌握 Redis面试必考50题 不仅仅是背诵答案,更要理解其背后的设计哲学。从底层数据结构的选择,到持久化与性能的权衡,再到高可用架构的演进,每一个知识点都体现了分布式系统在极端场景下的优化思路。希望本文能为您的面试准备提供清晰的脉络和深度的见解。

如果您发现本文内容有遗漏或需要进一步探讨的细节,欢迎在评论区交流。关注 考Acca,获取更多技术干货。