一、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 底层使用跳表而非红黑树,主要原因如下:
- 范围操作更友好:跳表可以更容易地进行范围查询(如 zrangebyscore),时间复杂度为 O(logN + n),而红黑树需要中序遍历。
- 实现更简单:跳表的插入删除操作比红黑树简单得多,且性能损耗极小。
- 缓存命中率:跳表是顺序访问内存,而红黑树是随机访问,跳表对 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题 中,双写一致性是难点。推荐策略:
- 先更新数据库,再删除缓存(Cache Aside Pattern):这是最常用的策略。虽然存在短暂不一致,但比先删缓存再更库更安全。
- 延时双删:先删缓存,更新数据库,再休眠一会儿删缓存。解决并发更新导致缓存残留问题。
- 订阅 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,获取更多技术干货。