Redis高频面试题汇总:从基础到高级全覆盖

一、基础概念篇

1.1 Redis核心定义与特性

Redis(Remote Dictionary Server) 是一个开源的、基于内存的高性能键值存储系统,支持多种数据结构(字符串、哈希、列表、集合、有序集合等),具备持久化、高可用、分布式扩展等特性。其核心优势体现在:

  • 极致性能:单线程模型结合内存存储,读写速度达11万次/秒(读)和8万次/秒(写),远超传统磁盘数据库。

  • 丰富数据结构:支持五种基础数据结构及高级模块(如HyperLogLog、Geo、BloomFilter),满足多样化业务场景。

  • 持久化机制:通过RDB快照和AOF日志实现数据持久化,保障故障恢复能力。

  • 高可用架构:主从复制、哨兵模式和集群模式支持自动故障转移,确保服务连续性。

1.2 Redis与Memcached的核心区别

对比维度RedisMemcached
数据结构 支持复杂类型(哈希、列表等) 仅支持简单键值对
持久化 支持RDB/AOF持久化 无持久化能力
线程模型 单线程(Redis 6.0前) 多线程
集群支持 原生支持集群模式 需依赖客户端实现分片
内存管理 支持数据过期淘汰和LRU策略 仅支持LRU淘汰
适用场景 缓存、消息队列、分布式锁等 简单缓存场景

典型面试题
Q:为什么Redis选择单线程模型仍能保持高性能?
A

  1. 内存操作:所有数据存储在内存中,避免磁盘I/O延迟。

  2. IO多路复用:基于epoll/kqueue实现非阻塞网络IO,单线程高效处理大量连接。

  3. 避免锁竞争:单线程消除多线程切换和锁开销,保证原子性操作。

  4. 高效数据结构:哈希表、跳表等设计使操作时间复杂度为O(1)或O(logN)。

二、数据结构与高级特性

2.1 五大核心数据结构详解

字符串(String)

  • 场景:缓存用户信息、计数器、分布式锁。

  • 示例

    SETuser:1001"{\"name\":\"Alice\",\"age\":25}"EX3600#存储JSON对象并设置过期时间
    INCRviews:page1#原子递增计数器

哈希(Hash)

  • 场景:存储对象属性(如用户信息、商品详情)。

  • 优势:避免序列化开销,支持字段级操作。

  • 示例

    HSETproduct:100"price"99.9"stock"100#存储商品价格和库存
    HINCRBYproduct:100"stock"-1#减少库存

列表(List)

  • 场景:消息队列、最新消息排序、分页查询。

  • 操作

    LPUSHmessages"msg1""msg2"#从左侧插入消息
    BRPOPmessages0#阻塞式从右侧弹出消息(超时时间0表示无限等待)

集合(Set)

  • 场景:标签系统、共同关注、去重。

  • 运算

    SADDtags:article1"tech""redis"#添加标签
    SINTERtags:article1tags:article2#获取两篇文章的共同标签

有序集合(Sorted Set)

  • 场景:排行榜、优先级队列、范围查询。

  • 示例

    ZADDleaderboard1000"Alice"950"Bob"#添加分数和用户
    ZREVRANGEleaderboard02WITHSCORES#获取前三名(降序)

2.2 高级特性与模块

HyperLogLog

  • 用途:基数统计(如UV计算),仅需12KB内存即可估算2^64个元素的基数。

  • 示例

    PFADDuv:20250811"user1""user2""user3"#添加用户
    PFCOUNTuv:20250811#获取独立用户数

Geo

  • 用途:地理位置存储与查询(如附近的人、外卖配送范围)。

  • 示例

    GEOADDlocations116.40439.915"Beijing"#添加经纬度坐标
    GEORADIUSlocations116.40439.91510km#查询10公里内的地点

Redis Stream

  • 用途:消息队列(支持消费者组、消息回溯)。

  • 示例

    XADDorders*item"book"quantity2#添加消息
    XREADGROUPGROUPgroup1consumer1COUNT1STREAMSorders>#消费者组读取消息

三、持久化与高可用

3.1 持久化机制对比

机制RDB(快照)AOF(日志)
原理 定期生成内存数据二进制快照 记录所有写操作命令
优点 文件紧凑、恢复速度快 数据安全性高、支持秒级持久化
缺点 可能丢失最后一次快照后的数据 文件体积大、恢复速度慢
适用场景 对性能要求高,容忍少量数据丢失 对数据安全性要求高

混合持久化(Redis 4.0+):结合RDB和AOF优势,生成RDB格式的全量数据+AOF格式的增量日志,平衡恢复速度与数据安全性。

3.2 高可用架构设计

主从复制(Master-Slave)

  • 原理:主节点处理写操作,异步同步到从节点;从节点仅处理读操作。

  • 配置

    SLAVEOF192.168.1.1006379#将当前节点设为从节点

哨兵模式(Sentinel)

  • 功能:监控主从节点健康状态,自动故障转移。

  • 工作流程

  1. 哨兵集群定期检查主节点存活状态。

  2. 主节点故障时,通过Raft算法选举新的主节点。

  3. 更新从节点配置,指向新主节点。

集群模式(Cluster)

  • 分片机制:使用哈希槽(16384个槽)分配数据,每个节点负责部分槽位。

  • 扩容:通过CLUSTER MEET命令添加新节点,使用CLUSTER ADDSLOTS重新分配槽位。

  • 故障处理:当多数主节点无法联系时,集群进入不可用状态。

四、性能优化与故障排查

4.1 常见性能问题与解决方案

大Key问题

  • 现象:单个Key存储数据量过大(如百万级元素的列表),导致读写延迟高、内存不均。

  • 解决方案

  1. 拆分:将大Key拆分为多个小Key(如user:1001:orders:1user:1001:orders:2)。

  2. 压缩:使用ZSTD等压缩算法存储数据。

  3. 异步加载:分页查询大列表,避免一次性加载全部数据。

热点Key问题

  • 现象:某些Key被高频访问,导致单节点负载过高。

  • 解决方案

  1. 本地缓存:在应用层使用Guava Cache缓存热点数据。

  2. 多级缓存:结合Redis和本地缓存,减少对Redis的直接访问。

  3. 读写分离:主节点写,从节点读,分散读压力。

慢查询问题

  • 现象:执行时间超过阈值的命令阻塞Redis。

  • 排查工具

    SLOWLOGGET10#获取最近10条慢查询日志
  • 优化策略

  1. 避免使用KEYS命令,改用SCAN渐进式遍历。

  2. 优化复杂命令(如SORTSUNION),拆分为多个简单命令。

4.2 内存淘汰策略

策略描述
noeviction 默认策略,内存满时禁止写入,返回错误。
volatile-lru 从设置了过期时间的键中淘汰最近最少使用(LRU)的键。
allkeys-random 从所有键中随机淘汰。
volatile-ttl 优先淘汰剩余生存时间(TTL)最短的键。

配置示例

CONFIGSETmaxmemory-policyvolatile-lru#设置内存淘汰策略

五、分布式与实战场景

5.1 分布式锁实现

基于SETNX的简单实现

SETlock:order123"1"NXEX10#原子操作:仅当key不存在时设置,并设置10秒过期时间

问题:未处理锁续期和误删问题。

Redisson改进方案

  • 看门狗机制:自动续期锁,防止业务未执行完锁过期。

  • Lua脚本释放锁:保证原子性,避免误删其他客户端的锁。

  • 代码示例

    RLocklock=redisson.getLock("orderLock");
    lock.lock(30,TimeUnit.SECONDS);//自动续期
    try{
    //业务逻辑
    }finally{
    lock.unlock();
    }

5.2 缓存一致性策略

Cache Aside Pattern(旁路缓存)

  1. 读流程:先查缓存,未命中则查数据库,写入缓存。

  2. 写流程:先更新数据库,再删除缓存(而非更新缓存,避免复杂一致性维护)。

问题:并发场景下可能存在缓存不一致(如线程A更新数据库但未删缓存时,线程B读取旧数据并写入缓存)。

延迟双删策略

publicvoidupdateData(Datadata){
redis.del(data.getId());//第一次删除缓存
db.update(data);//更新数据库
Thread.sleep(1000);//延时1秒
redis.del(data.getId());//第二次删除缓存
}

原理:通过延时删除覆盖可能存在的脏数据写入。

六、监控与运维

6.1 监控指标与工具

指标工具阈值建议
内存使用率INFO memory >80%时触发告警
命中率INFO stats
发布于 2025-09-13 02:11:40
分享
海报
167
上一篇:JavaScript 中使用闭包创建私有对象的高级技巧 下一篇:MySQL正则表达式REGEXP查询命令使用教程
目录

    忘记密码?

    图形验证码