一、Redis 基础概念
Redis 是什么?有哪些特点?
Redis 是一个开源的、基于内存的数据结构存储系统,可用于数据库、缓存和消息中间件。
特点:高性能(10万+ QPS)、单线程模型(6.0后支持多线程IO)、持久化、支持事务、发布订阅等。
Redis 与 Memcached 的区别?
Redis 支持更丰富的数据类型,Memcached 仅支持字符串。
Redis 支持持久化,Memcached 纯内存。
Redis 单线程模型(6.0后支持多线程IO),Memcached 多线程。
Redis 支持集群模式,Memcached 需客户端分片。
Redis 单线程为什么性能高?
纯内存操作,无上下文切换开销。
非阻塞 IO 多路复用(epoll/kqueue)。
单线程避免锁竞争问题(6.0 后引入多线程处理网络 IO,但核心逻辑仍单线程)。
二、Redis 数据结构与使用场景
Redis 支持哪些数据结构?举例说明应用场景
String:缓存、计数器(INCR)、分布式锁(SETNX)。
List:消息队列(LPUSH/RPOP)、最新消息排行。
Hash:存储对象(用户信息、商品详情)。
Set:标签系统、共同好友(SINTER)。
ZSet:排行榜(ZADD)、延迟队列(按时间戳排序)。
BitMap:用户签到、活跃统计。
HyperLogLog:UV 统计(去重计数)。
Stream:消息队列(支持消费者组,类似 Kafka)。
ZSet 底层实现原理?
使用 跳跃表(SkipList) + 哈希表 实现,支持 O(logN) 复杂度的范围查询和 O(1) 的单点查询。
Redis 如何实现分布式锁?
使用 SET key value NX EX timeout 命令(原子操作)。
需解决锁续期问题(看门狗机制)和锁误删问题(Lua 脚本验证值)。
推荐 Redlock 算法(多实例部署,半数以上成功才算获取锁)。
Redis 分布式锁原理
基于setNX命令,防止死锁需要设置过期时间
(早版本setNX和过期时间是两条指令,不是原子操作,需要引入lua,变成一条指令后就不用了),
防止过期时程序未完成,需要自动续期。自动续期可以使用redision的watchdog实现。
使用流程:先上锁,如果上锁成功则执行业务,最后释放锁。如果上锁失败则返回或重试等,
根据业务情况而定。
Redis 如何实现延时队列?
使用 sortedset,拿时间戳作为score,消息内容作为 key 调用 zadd 来生产消息,
消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。
三、Redis 持久化
RDB 和 AOF 的区别与优缺点?
RDB:
生成数据快照,文件小,恢复快。
缺点:可能丢失最后一次快照后的数据,大数据量时 fork 可能阻塞主线程。
AOF:
记录写操作命令,支持秒级持久化(appendfsync everysec)。
缺点:文件较大,恢复速度慢。
生产环境通常结合使用:AOF 保证数据安全,RDB 用于快速恢复。
AOF 重写(Rewrite)过程?
根据当前内存数据生成新的 AOF 文件,替换旧文件以缩小体积。
通过 bgrewriteaof 命令触发,fork 子进程完成,不影响主线程。
四、Redis 高可用与集群
主从复制原理?
全量同步:从节点发送 SYNC 命令,主节点生成 RDB 并传输,之后传输缓冲区的命令。
增量同步:主节点维护复制积压缓冲区,从节点断线重连后发送 PSYNC 命令同步偏移量。
哨兵(Sentinel)模式的作用?
监控主从节点状态,自动故障转移(主节点宕机时选举新主)。
提供配置中心功能,客户端通过哨兵获取主节点地址。
Redis Cluster 如何实现数据分片?
采用 哈希槽(Hash Slot) 分片(共 16384 个槽)。
每个节点负责部分槽位,客户端通过 CRC16(key) % 16384 计算槽位,直接路由到对应节点。
Redis Cluster 如何应对节点故障?
每个节点定期向其他节点发送 PING 命令,半数以上节点认为某主节点不可达时触发故障转移。
从节点升级为主节点,原主节点恢复后变为从节点。
五、Redis 应用场景与问题解决
缓存穿透、缓存击穿、缓存雪崩的区别与解决方案?
穿透:查询不存在的数据(恶意攻击)。
方案:布隆过滤器拦截、缓存空值。
击穿:热点 key 过期后高并发查询直接压到数据库。
缓存并发的问题通常发生在高并发的场景下,当一个缓存key过期时,因为访问这个缓存key 的请求量较大,
多个请求同时发现缓存过期,因此多个请求会同时访问数据库来查询最新数据,并且回写缓存,
这样会造成应用和数据库的负载增加,性能降低,由于并发较高,甚至会导致数据库被压死。
方案:互斥锁(Redis 或分布式锁)、永不过期(逻辑过期时间)。
雪崩:大量 key 同时过期或 Redis 宕机。
方案:随机过期时间、集群高可用、熔断降级。
如何保证缓存与数据库双写一致性?
读操作:先读缓存,未命中则读数据库并回写缓存。
写操作:先更新数据库,再删除缓存(延迟双删策略)。
最终一致性可通过消息队列或监听 binlog 异步同步。
大 Key 和热 Key 问题如何处理?
大 Key:拆分(Hash 分 field)、压缩、异步删除(UNLINK)。
热 Key:多级缓存(本地缓存)、打散到多个 key(添加随机后缀)。
六、Redis 性能优化
Redis 内存淘汰策略有哪些?
noeviction:当内存使用达到限制时,不执行任何回收操作。
volatile-lru:尝试回收最少使用的键(LRU),但仅限于在过期集合的键。
volatile-random:随机回收键,但仅限于在过期集合的键。
volatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键。
allkeys-lru:尝试回收最少使用的键(LRU)。
allkeys-random:随机回收键。
Pipeline 和 Lua 脚本的作用?
Pipeline:批量发送命令,减少网络往返时间(RTT)。
Lua 脚本:原子执行多个命令,避免竞态条件(如库存扣减)。
七、其他高频问题
Redis 事务(MULTI/EXEC)的 ACID 特性?
满足原子性(全部执行或全部不执行。
无回滚(仅语法错误会取消事务)。
隔离性(单线程无并发问题)。
不保证持久性(依赖持久化配置)。
Redis 6.0 多线程模型原理?
多线程仅用于处理网络 IO(读写 socket),命令执行仍为单线程,保证原子性。
Redis 的慢查询如何监控?
通过 slowlog get 命令查看,需配置阈值(slowlog-log-slower-than)。
什么是脑裂?
在 Redis 高可用架构(如主从复制 + 哨兵模式)中,当网络分区(Network Partition)导致主节点与哨兵、
从节点之间的通信中断时,可能会出现多个主节点同时存在的现象,称为脑裂。例如:
原主节点因网络问题被哨兵判定为宕机,触发故障转移选举出新主节点。
但原主节点实际上仍在运行(可能仍在接受客户端写入),导致集群中存在两个主节点,数据不一致。
脑裂的危害
数据丢失:客户端可能同时向两个主节点写入数据,当原主节点恢复后,会被哨兵降级为从节点,
并清空自身数据以同步新主节点数据,导致原主节点上的写入数据丢失。
数据不一致:两个主节点独立接受写入,数据无法自动合并。
Redis 如何避免脑裂?
1、配置 min-slaves-to-write 和 min-slaves-max-lag
主节点需满足以下条件才允许写入:
min-slaves-to-write 1 # 至少存在 1 个从节点
min-slaves-max-lag 10 # 从节点复制延迟不超过 10 秒
当主节点发现从节点数量不足或复制延迟过高时,拒绝写入请求,避免与原主节点同时写入数据。
2、合理设置哨兵参数
down-after-milliseconds:适当增大主节点判定不可用的超时时间(如30秒),避免因网络抖动误判主节点宕机。
quorum:设置合理的哨兵投票数(半数以上确认才触发故障转移),防止少数哨兵误操作。
3、客户端重试机制
客户端在写入失败后,应检查当前主节点是否已切换,避免持续向旧主节点写入。
4、在 Redis Cluster 中,通过 多数派原则 和 Gossip 协议 避免脑裂:
脑裂后的数据恢复
若已发生脑裂,需人工介入:
保留新主节点的数据(因其被多数哨兵认可)。
将原主节点恢复为从节点前,手动备份其数据并对比差异,选择性合并(需业务逻辑支持)。
八、实战经验与扩展
如何选择 Redis 集群方案?
小规模用哨兵+主从,大规模数据用 Redis Cluster。
Redis 的常见监控指标:内存使用率、QPS、连接数、命中率、慢查询。
Redis 7.0 新特性:Function(服务端脚本)、Multi-part AOF 等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。