Redis.全部面试题

Redis 热key

方法 优点 缺点
redis-cli --hotkeys 简单易用,快速定位热点 扫描时间限制,性能影响
Keyspace Notifications 实时监控,灵活 性能开销,复杂度较高
慢查询日志 发现耗时热点 只关注慢查询,不全
采样分析与监控系统 全面,结合业务数据 需要搭建监控系统
自定义访问计数器 精准,业务可控 额外开销,需要业务配合

Redis Cluster 故障转移流程

Redis Cluster 支持自动故障转移(Failover)机制,在主节点故障时由其从节点接管,以保证服务的高可用性。


故障转移流程

主节点 A 挂了
    ↓
从节点 A1 检测到主节点 A 不可达(PFAIL)
    ↓
多个节点标记 A 为 FAIL(确认故障)
    ↓
从节点 A1 准备发起故障转移(此时进入随机延迟等待⏱️)
    ↓
延迟结束 → 发起选举(请求投票)
    ↓
其他主节点投票支持 A1 升级为主
    ↓
A1 成为新主节点,接管槽位
    ↓
集群更新槽位映射,完成转移

故障转移步骤

1. 故障检测(Failure Detection)

  • 节点之间使用 Gossip 协议定期发送 PING
  • 若某节点超过 cluster-node-timeout 未响应 → 标记为 PFAIL(疑似故障)。
  • 若多个节点将该节点标记为 PFAIL,则达成共识标记为 FAIL(确认故障),并广播此状态。

2. 从节点发起故障转移(Failover)

  • 发现主节点 FAIL 的从节点,在随机延迟后准备发起转移。
  • 满足条件的从节点开始请求授权进行主从切换。

3. 投票选举新主节点

  • 发起选举的从节点向其他主节点发送投票请求(FAILOVER_AUTH_REQUEST)。
  • 若获得半数以上主节点的投票支持 → 当选为新主节点。

4. 主从角色切换

  • 被选中的从节点脱离旧主节点关系,升级为主节点。
  • 接管原主节点负责的槽位(Slot)。

5. 槽位与拓扑更新

  • 新主节点广播角色变更。
  • 所有节点更新其槽位到节点的映射表,保持集群一致。

相关注意事项

项目 说明
随机延迟 防止多个从节点同时发起故障转移导致冲突
投票机制 需获得半数以上主节点支持(包括自己)
优先级 slave-priority 值越高,从节点越优先成为主节点
主节点数量要求 故障转移要求至少 3 个主节点(保证多数派)
手动触发 可使用 CLUSTER FAILOVER 命令主动执行切换

Redis Cluster 两个节点脑裂问题

什么是脑裂?

脑裂指的是集群因网络分区或通信故障,导致集群分裂成两个或多个子集群,每个子集群都认为自己是主集群,进而导致数据不一致和服务混乱。

Redis Cluster 两个节点的脑裂问题

情况 说明
主节点数量 = 2 集群无法形成“多数派”,因为多数派至少需要超过半数节点。
网络分区发生 假设两个主节点 A、B 之间网络断开,两边各自认为对方失联。
每个节点单独判定对方 FAIL 节点 A 认为 B 挂了,节点 B 也认为 A 挂了。
双方都认为自己是正常主节点 由于没有多数派原则,两边都不会放弃自己的主节点身份。
结果 产生两个“活跃主节点”,数据写入不同步,导致数据严重不一致。

为什么两个节点无法避免脑裂?

  • 没有多数派投票,只有两个节点时,故障判定需要 2/2 节点同意,网络断开后无法达成共识。
  • 没有第三方裁决节点,缺乏“仲裁者”角色,无法判定真正的故障方。

Redis Cluster 扩容和缩容

一、Redis Cluster 扩容(增加节点)

1. 新节点加入集群

  • 新节点启动时,先以空槽分配状态加入集群。
  • 通过 CLUSTER MEET <ip> <port> 命令,将新节点加入集群。

2. 分配槽到新节点

  • 现有节点需要将部分槽迁移给新节点,通常通过客户端工具或手动命令操作。
  • 迁移过程:
    • 发送 CLUSTER SETSLOT <slot> MIGRATING <node_id> 给源节点,表示该槽开始迁移。
    • 发送 CLUSTER SETSLOT <slot> IMPORTING <new_node_id> 给目标节点,表示该槽开始导入。
    • 将该槽相关的数据(key)逐个迁移到新节点。
    • 迁移完成后,更新槽映射,槽归新节点所有。

3. 重新平衡槽分布

  • 通过迁移槽实现集群负载均衡,避免数据热点。

二、Redis Cluster 缩容(移除节点)

1. 将待移除节点槽迁移走

  • 将待移除节点负责的槽,逐步迁移到其他节点。
  • 过程同扩容的槽迁移过程。

2. 从集群中剔除节点

  • 迁移完成后,通过 CLUSTER FORGET <node_id> 命令让其他节点忘记该节点。
  • 该节点退出集群。

三、槽迁移细节

  • 槽是 Redis Cluster 的数据分片单位,总共 16384 个槽。
  • 扩容和缩容都是通过槽的转移实现数据的动态调整。
  • 槽迁移过程中,集群仍可提供读写服务,迁移数据过程支持在线状态。

Redis 的 Twemproxy(也叫 Nutcracker)是一个开源的代理中间件,它的主要作用是:


Twemproxy 的作用

  1. 代理客户端请求
  • Twemproxy 作为客户端和多个 Redis 服务器之间的代理层,接收客户端请求后,根据配置将请求路由到对应的 Redis 实例。
  • 客户端只连接 Twemproxy,简化了客户端对多 Redis 节点的管理。
  1. 实现统一的分片(sharding)机制
  • Twemproxy 支持基于哈希的分片,将 key 映射到不同的 Redis 节点,实现数据的分片分布。
  • 透明地支持多节点 Redis 集群模式,客户端无需感知多个 Redis 实例。
  1. 简化客户端连接管理
  • 客户端只需连接 Twemproxy 一个地址,避免管理多个 Redis 连接。
  • 减少客户端连接数,减轻 Redis 服务器的压力。
  1. 支持读写分离
  • Twemproxy 支持将读请求路由到从节点,写请求路由到主节点,提升性能。
  1. 提升系统扩展性
  • 支持动态添加和移除 Redis 节点,方便扩展和维护。

Redis 内存分配碎片

Redis 的内存碎片是指:Redis 实际分配的内存空间大于其存储的数据所需内存的情况,主要是由于内存分配、回收不均造成的。这种碎片可能导致 Redis 占用大量系统内存,即使实际数据量并不大。


🧱 一、内存碎片的产生原因

1. 内存分配器特性

Redis 使用不同版本的内存分配器(如 jemallocglibc),这些分配器为性能优化会预分配或对齐内存块,导致:

场景 描述
小对象分配 分配器按最小粒度(如 8B、16B)对齐,浪费空间
对象删除 被删除对象的内存未及时释放,形成“空洞”
内存池空闲 分配器维护的 arena、chunk 等可能长期保持未用但保留状态

2. 键值变更频繁

  • Redis 中大量键频繁更新、删除、重建,导致内存分配释放不均衡;
  • 特别是使用复杂结构(如 list、set、zset)时更容易产生碎片。

3. 大对象释放

  • Redis 释放大型对象后,分配器未及时将内存归还系统,而是“保留”下来,等待再次复用。

4. 内存碎片与 RDB/AOF 重写

  • Redis 在 RDB 保存或 AOF 重写时会分配新内存空间临时存储数据;
  • 重写结束后旧内存释放,新内存保留,会增加碎片率。

📊 二、如何查看内存碎片率?

使用 Redis 命令:

INFO MEMORY

关键字段:

used_memory:        实际使用的内存(字节)
used_memory_rss:    向操作系统申请的总物理内存
mem_fragmentation_ratio = used_memory_rss / used_memory
  • 正常范围:1.0 ~ 1.5
  • 超过 1.5:说明碎片严重,可能需要优化

🧰 三、解决或缓解内存碎片的方式

方法 说明
重启 Redis 释放全部内存,由操作系统重新分配,效果显著但有停机风险
使用 jemalloc 默认配置更优,管理碎片更好(推荐替代 glibc)
手动触发 MEMORY PURGE(Redis 4.0+) 清理 jemalloc 中空闲未使用的 arena 空间
内存监控与热点管理 减少频繁删除/创建对象,控制内存抖动行为
合理配置 maxmemory 策略 避免 Redis 内存占用无限扩张(使用 LFU、LRU 等)

✏️ 四、相关命令说明

MEMORY STATS     # 查看 jemalloc 内存使用详情
MEMORY PURGE     # 主动请求释放 jemalloc 的未使用内存

Pipeline 和 Multi / Exec 的区别

特性 Pipeline Multi / Exec
作用 减少网络往返次数,提高吞吐 实现事务,保证命令原子性执行
事务支持 ❌ 不是事务,不保证原子性 ✅ 支持事务,命令按序原子执行
错误处理 单个命令出错不影响其他命令 编译阶段出错不执行,执行阶段部分失败不回滚
命令执行 一次发送多个命令,服务端依次执行并返回结果 MULTI 开启事务,EXEC 一次性提交所有命令执行
返回机制 所有命令的结果一起返回 所有命令打包在 EXEC 后返回
客户端资源占用 占用较多内存(命令缓冲) 占用少量内存
使用场景 高性能批量读写 需要多个命令一致性(如账户转账)

AOF重写期间的增量数据如何处理?

AOF 重写期间新增的数据会被写入一个“增量缓冲区(AOF rewrite buffer)”,等子AOF重写期间的增量数据如何处理?进程重写完毕后,主进程会把这些增量写操作追加到新 AOF 文件的末尾,确保最终新 AOF 文件完整无缺。

Redis的jemalloc分配器有什么特点?

特点 说明
1. 低内存碎片率 jemalloc 能更好地管理内存块,避免频繁分配和释放带来的碎片问题,提升内存使用效率。
2. 多线程优化(多 Arena) 支持多个 arena,避免线程间竞争;虽然 Redis 主线程是单线程的,但后台 AOF、RDB、集群等线程也受益于此。
3. 快速分配与释放 采用固定大小内存池(bin + slab)技术,适用于 Redis 中大量小对象的频繁分配与释放。
4. 更好的内存可观测性 提供丰富的统计与监控接口(如 je_malloc_stats_print),便于追踪内存使用。
5. 稳定性高 jemalloc 在长期运行的大型 Redis 服务中表现出更稳定的内存使用和性能。
used_memory:Redis 实际使用的内存

used_memory_rss:Redis 进程从操作系统申请的总内存(可能包含碎片)

allocator_allocated:jemalloc 实际分配的总内存

allocator_active:jemalloc 申请的活跃内存

allocator_frag_ratio:碎片比

big key 有什么性能问题

问题类型 影响描述
阻塞主线程 Redis 是单线程模型,访问 bigkey 会导致主线程长时间阻塞,影响整个实例响应。
删除慢 DELUNLINK bigkey 时,尤其是集合类键(如一个包含百万元素的 Hash),DEL 会瞬时清理,阻塞明显
网络传输开销大 读取 bigkey(如 GET 一个 10MB 的 String)会造成 带宽占用高、延迟大。
主从同步压力大 主库发送 bigkey 到从库,会拖慢同步速度,甚至引发复制中断。
AOF 或 RDB 持久化成本高 保存或加载 bigkey 成本大,尤其是在重启恢复时显著拉长冷启动时间。
posted @ 2025-05-17 12:19  不报异常的空指针  阅读(12)  评论(0)    收藏  举报