一、源码与架构原理
-
Redis是单线程吗?具体是如何实现的?
- Redis主线程处理命令,采用I/O多路复用(epoll/kqueue/select)异步监听客户端请求,避免了多线程上下文切换开销。
-
Redis的数据结构底层实现?
- 字符串(String)底层是简单动态字符串(SDS),支持自动扩容,避免了传统C字符串的缺点。
- Hash内部采用两种编码:ziplist(压缩列表)和hashtable,自动根据大小切换。
- List底层是quicklist,结合双向链表和ziplist,兼顾内存和性能。
- Set用哈希表或整数集合(intset)实现。
- ZSet(有序集合)用跳表(skiplist)和哈希表结合实现。
-
什么是Redis的慢查询日志?如何定位性能瓶颈?
- Redis会记录执行时间超过阈值的命令。分析慢查询日志结合命令统计,可以发现热点命令和性能瓶颈。
-
Redis是如何保证数据的原子性的?
- 单线程顺序执行命令,命令执行过程中不会被打断,保证原子性。Lua脚本也保证单条脚本内所有操作原子执行。
-
Redis的RDB持久化是如何实现的?
- 使用fork子进程创建快照,子进程负责写入RDB文件,主进程继续处理请求,避免阻塞。
-
AOF持久化的工作机制及重写机制?
- 追加写日志记录每个写操作,重写时生成新的最小化AOF文件,防止文件膨胀。
二、集群与高可用
-
Redis集群的分片原理是怎样的?
- 使用16384个槽(slot)分配给各个节点,键通过CRC16(key) % 16384计算槽位,槽分配到不同节点,实现数据分片。
-
Redis集群中槽迁移的流程?
- 新节点加入后,部分槽从旧节点迁移到新节点,迁移过程中会转发请求保证一致性。
-
Redis哨兵(Sentinel)的工作流程?
- 监控主从节点状态,判断主节点宕机后,选举新主节点,通知客户端重新连接。
-
什么是Redlock算法?它解决了什么问题?
- 分布式锁算法,通过多个Redis实例获取锁,防止单点故障导致锁失效。
-
Redis集群如何保证强一致性?
- Redis默认是最终一致性,集群中采用异步复制,可能存在数据丢失,强一致性需要业务层做保障。
三、性能优化与调优
-
Redis内存优化有哪些技巧?
- 使用哈希小对象编码(hash-max-ziplist-entries和hash-max-ziplist-value)
- 减少key和value的冗余长度
- 合理使用压缩列表和快速列表
- 设置合理过期策略,避免大key
-
Redis大key问题怎么处理?
- 避免存储过大的字符串、列表、集合等
- 使用分片拆分大数据
- 监控大key,定期清理或拆分
-
如何避免缓存穿透、缓存击穿和缓存雪崩?
- 缓存穿透:使用布隆过滤器或空值缓存
- 缓存击穿:加互斥锁,或者用永不过期的热点缓存
- 缓存雪崩:设置过期时间随机,分散缓存失效时间
-
Redis为什么会阻塞?如何避免?
- 大key操作(如keys、flushall)
- 持久化fork过程CPU或内存压力
- 使用scan替代keys,合理配置持久化,避免大key
-
Redis的慢日志怎么调优?
- 调整慢查询阈值,定位高耗时命令,优化数据结构和访问方式
四、实战题
-
设计一个基于Redis的限流方案。
- 使用计数器和过期时间实现固定窗口限流
- 使用滑动窗口或令牌桶算法实现更精准限流(Lua脚本)
-
如何用Redis实现分布式队列?
- 使用List结构的lpush/rpop
- 结合阻塞命令(BLPOP)实现消息队列功能
-
你遇到过Redis宕机怎么办?如何恢复数据?
- 查看AOF和RDB文件恢复数据
- 使用哨兵自动切换主节点
- 评估数据丢失风险,做好备份
-
Redis在高并发场景中怎么保证写操作性能?
- 使用pipeline减少网络往返
- 适当使用Lua脚本批量处理
- 减少大key操作,避免阻塞