redis面试问题


持久化

Redis 是内存数据库,为了避免因故障(如服务器重启、断电等)导致数据丢失,提供了多种数据持久化机制,下面详细介绍常见的持久化方式。

RDB(Redis Database)持久化

RDB 是 Redis 默认的持久化方式,它将某一时刻 Redis 内存中的数据生成二进制快照保存到磁盘。

工作原理

  • 手动触发:使用 SAVEBGSAVE 命令。SAVE 会阻塞 Redis 主线程,直到快照生成完成;BGSAVE 则会派生出一个子进程来创建快照,主线程继续处理请求。
  • 自动触发:通过配置文件 redis.conf 中的 save 参数设置触发条件,例如 save 900 1 表示 900 秒内若有 1 个键发生变化,就生成快照。

配置示例

1
2
3
4
save 900 1
save 300 10
save 60 10000

优点

  • 文件紧凑:RDB 文件是二进制文件,体积小,适合备份和灾难恢复。
  • 恢复速度快:加载 RDB 文件到内存时,直接解析二进制数据,速度比 AOF 快。

缺点

  • 数据易丢失:若在两次快照之间发生故障,会丢失这期间的数据。
  • 阻塞风险SAVE 命令会阻塞主线程,BGSAVE 创建子进程也会有一定性能开销。

AOF(Append Only File)持久化

AOF 持久化是将 Redis 执行的写命令追加到日志文件,以记录数据变化。

工作原理

  • Redis 执行写命令时,先将命令写入 AOF 缓冲区,再根据配置策略将缓冲区内容同步到磁盘。
  • 有三种同步策略:
    • always:每次写操作都同步到磁盘,数据安全性最高,但性能最差。
    • everysec:每秒同步一次,兼顾性能和数据安全,是默认配置。
    • no:由操作系统决定何时同步,性能最好,但数据安全性最低。

配置示例

1
2
3
appendonly yes
appendfsync everysec

优点

  • 数据安全:能最大程度减少数据丢失,always 策略几乎不丢失数据。
  • 易读可修改:AOF 文件是文本文件,可直接查看和修改。

缺点

  • 文件体积大:AOF 文件记录写命令,体积通常比 RDB 文件大。
  • 恢复速度慢:恢复数据时需重新执行 AOF 文件中的命令,耗时较长。

混合持久化

Redis 4.0 引入混合持久化,结合了 RDB 和 AOF 的优点。

工作原理

  • 执行 AOF 重写时,先将当前内存数据以 RDB 格式写入 AOF 文件,再将重写后的 AOF 日志追加到文件末尾。

配置示例

1
2
aof-use-rdb-preamble yes

优点

  • 恢复速度快:前半部分 RDB 格式数据加载快。
  • 数据安全:后半部分 AOF 日志记录重写后的数据变化。

选择建议

  • 数据安全要求不高:使用 RDB 持久化,简单高效,适合备份。
  • 数据安全要求高:使用 AOF 持久化,可选择 everysec 策略。
  • 兼顾性能和数据安全:使用混合持久化。

哨兵模式

Redis 哨兵(Sentinel)机制是 Redis 高可用性的解决方案,它可以自动监控 Redis 主从节点的状态,在主节点出现故障时自动进行故障转移,保证 Redis 服务的连续性。下面从多个方面详细介绍 Redis 哨兵机制。

基本概念

  • 哨兵节点:独立运行的 Redis 进程,多个哨兵节点组成哨兵集群,共同监控 Redis 主从节点状态,执行故障转移操作。
  • 主节点(Master):负责处理客户端的写操作,同时将数据同步给从节点。
  • 从节点(Slave):从主节点复制数据,处理客户端的读操作,当主节点故障时,可被提升为新的主节点。

工作原理

1. 监控(Monitoring)

哨兵节点会定期向 Redis 主从节点发送 PING 命令,检测节点是否存活。同时,哨兵之间也会互相通信,交换关于主从节点的状态信息。例如,默认情况下,哨兵每 10 秒向主从节点发送 INFO 命令,获取节点的最新信息。

2. 通知(Notification)

当哨兵发现某个 Redis 节点出现故障时,会通过发布 - 订阅机制通知其他哨兵和客户端。客户端可以订阅哨兵的消息,及时了解 Redis 节点的状态变化。

3. 自动故障转移(Automatic Failover)

当多数哨兵节点都认为主节点不可用(主观下线和客观下线)时,会触发自动故障转移流程:

  • 主观下线(Subjective Down,SDOWN):单个哨兵节点认为主节点不可用,可能是网络延迟等原因导致。
  • 客观下线(Objective Down,ODOWN):当足够数量(由配置文件中的 quorum 参数指定)的哨兵节点都认为主节点不可用时,主节点被判定为客观下线,触发故障转移。
  • 选举领头哨兵:多个哨兵节点会选举出一个领头哨兵,由它负责执行故障转移操作。
  • 选择新主节点:领头哨兵从原主节点的从节点中选择一个作为新的主节点,选择规则通常是根据从节点的优先级、复制偏移量和运行 ID 等。
  • 更新配置:领头哨兵将新主节点的信息通知给其他从节点,让它们从新主节点复制数据,同时更新客户端的配置信息。

配置示例

1. 配置主从节点

主节点配置 redis.conf

1
2
port 6379

从节点配置 redis.conf

1
2
3
port 6380
slaveof <master_ip> 6379

2. 配置哨兵节点

创建 sentinel.conf 文件:

1
2
3
4
5
6
7
8
9
10
port 26379
# 监控主节点,mymaster 是主节点的名称,<master_ip> 是主节点的 IP 地址,6379 是主节点的端口,2 是 quorum 值
sentinel monitor mymaster <master_ip> 6379 2
# 主节点主观下线的超时时间,单位为毫秒
sentinel down-after-milliseconds mymaster 30000
# 故障转移时,最多可以有多少个从节点同时对新主节点进行同步
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间,单位为毫秒
sentinel failover-timeout mymaster 180000

3. 启动哨兵节点

1
2
redis-sentinel /etc/redis/sentinel.conf

优点

  • 高可用性:自动检测主节点故障并进行故障转移,减少服务中断时间。
  • 简单易用:配置相对简单,不需要复杂的管理操作。
  • 监控功能:提供节点状态监控和通知功能,方便运维人员及时发现问题。

缺点

  • 部署复杂度:需要部署多个哨兵节点和 Redis 主从节点,增加了部署和管理的复杂度。
  • 故障转移时间:故障转移过程需要一定时间,可能会导致部分请求失败。

集群

Redis 集群是 Redis 提供的分布式解决方案,用于在多个 Redis 节点间分片存储数据,实现高可用、可扩展的 Redis 服务。下面从多个方面详细介绍 Redis 集群。

基本概念

  • 槽(Slot):Redis 集群将整个键空间划分为 16384 个槽(编号 0 - 16383)。每个键通过 CRC16 算法计算后对 16384 取模,得到对应的槽编号,数据会被存储到负责该槽的节点上。
  • 主节点(Master):负责处理槽的读写操作,每个主节点负责一部分槽。当主节点故障时,对应的从节点会被提升为新主节点。
  • 从节点(Slave):复制对应主节点的数据,当主节点不可用时,从节点可被选举为新主节点,保障服务高可用。

工作原理

数据分片

客户端向 Redis 集群发送命令时,先计算键对应的槽编号,再将命令发送到负责该槽的主节点。若客户端不知道键对应的节点,会收到 MOVED 重定向信息,指引客户端到正确节点。

节点通信

Redis 集群节点间使用 Gossip 协议通信,节点定期交换彼此状态、故障信息等。通过 Gossip 协议,节点能快速感知集群状态变化,如节点加入、退出或故障等。

故障转移

  • 故障检测:节点间通过 PING 消息互相检测状态,若某个节点长时间未响应,会被标记为疑似下线(PFAIL)。当多数节点都认为该节点下线,会将其标记为已下线(FAIL)。
  • 故障转移:当主节点下线,其从节点会发起选举,竞争成为新主节点。选举成功的从节点会接管原主节点负责的槽,继续提供服务。

搭建 Redis 集群示例

1. 准备节点配置

假设搭建 3 个主节点和 3 个从节点,每个节点配置文件类似如下:

1
2
3
4
5
6
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes

其他节点只需修改 portcluster-config-file 中的端口号。

2. 启动节点

分别启动 6 个 Redis 节点:

1
2
3
4
5
6
7
redis-server redis-7000.conf
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
redis-server redis-7004.conf
redis-server redis-7005.conf

3. 创建集群

使用 redis-cli 创建集群,指定主从关系:

1
2
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1

--cluster-replicas 1 表示每个主节点有 1 个从节点。

4. 验证集群

连接任意节点,使用 CLUSTER INFOCLUSTER NODES 命令查看集群信息:

1
2
3
4
redis-cli -c -p 7000
127.0.0.1:7000> CLUSTER INFO
127.0.0.1:7000> CLUSTER NODES

优点

  • 高可用性:每个主节点有从节点备份,主节点故障时自动故障转移,保障服务不中断。
  • 可扩展性:可方便地添加或移除节点,动态调整集群容量。
  • 高性能:数据分片存储,多个节点并行处理请求,提升系统吞吐量。

缺点

  • 管理复杂度:集群部署和管理相对复杂,需要维护多个节点和它们之间的关系。
  • 客户端支持:部分客户端需要支持集群模式,否则需要额外处理重定向等问题。
  • 数据一致性:由于采用异步复制,在故障转移时可能存在少量数据丢失。

主节点选举

在 Redis 中有两种常见场景涉及主节点选举,分别是 Redis 哨兵(Sentinel)模式和 Redis 集群模式,下面为你详细介绍这两种模式下主节点选举的机制。

Redis 哨兵(Sentinel)模式主节点选举

在 Redis 哨兵模式中,当主节点出现故障时,哨兵集群会共同协作完成故障转移,从从节点中选举出新的主节点。其选举流程如下:

1. 主观下线与客观下线

  • 主观下线(SDOWN):单个哨兵节点通过向 Redis 主节点发送 PING 命令,若在指定时间(由 down-after-milliseconds 配置)内未收到有效回复,该哨兵会将主节点标记为“主观下线”。
  • 客观下线(ODOWN):当认为主节点主观下线的哨兵数量达到配置的 quorum 值时,该主节点会被判定为“客观下线”,此时触发故障转移流程。

2. 选举领头哨兵

多个哨兵节点需要选举出一个领头哨兵来执行故障转移操作,选举过程基于 Raft 算法的领导者选举机制:

  • 每个哨兵节点有一个选举超时时间,当该时间到达时,节点会发起选举,将自己的选举次数加 1,并向其他哨兵节点发送请求投票的消息。
  • 其他哨兵节点收到请求后,若还未投票给其他节点,则会回复同意投票,若已经投票则拒绝。
  • 当某个哨兵节点收到超过半数哨兵节点的同意投票时,该节点成为领头哨兵。

3. 选择新主节点

领头哨兵从原主节点的从节点中选择一个作为新的主节点,选择规则如下:

  1. 排除不健康的从节点:排除处于主观下线、客观下线、断线或与原主节点失联时间过长的从节点。
  2. 选择优先级高的从节点:根据从节点的 slave-priority 配置,值越小优先级越高。若 slave-priority 为 0,则该从节点不会被选为新主节点。
  3. 选择复制偏移量大的从节点:若优先级相同,则选择复制偏移量最大(即与原主节点数据最接近)的从节点。
  4. 选择运行 ID 小的从节点:若复制偏移量也相同,则选择运行 ID 最小的从节点。

4. 故障转移

  • 领头哨兵将选中的从节点升级为新的主节点,通过发送 SLAVEOF no one 命令。
  • 通知其他从节点复制新的主节点,发送 SLAVEOF <new_master_ip> <new_master_port> 命令。
  • 更新客户端配置信息,让客户端连接到新的主节点。

Redis 集群模式主节点选举

在 Redis 集群中,当某个主节点下线时,其对应的从节点会发起选举成为新的主节点,选举流程如下:

1. 故障检测

  • 节点间通过 PING 消息互相检测状态,若某个主节点在 cluster-node-timeout 时间内未响应,会被标记为疑似下线(PFAIL)。
  • 当集群中超过半数的主节点都认为该主节点下线时,会将其标记为已下线(FAIL)。

2. 从节点发起选举

  • 下线主节点的从节点发现主节点下线后,会等待一段时间(等待时间与从节点的复制偏移量有关,偏移量越大等待时间越短),然后发起选举。
  • 从节点会向集群中的其他主节点发送请求投票的消息,请求其他主节点为自己投票。

3. 主节点投票

  • 每个参与投票的主节点在一个配置纪元(Epoch)内只能投一票,先到先得。
  • 从节点收到超过半数主节点的投票后,会赢得选举,成为新的主节点。

4. 接管槽位

新的主节点会接管原主节点负责的槽位,继续处理客户端的请求。

选举失败处理

在 Redis 中,哨兵模式和集群模式下都存在主节点选举流程,若选举失败,不同模式会有不同的处理方式,下面分别介绍。

Redis 哨兵模式选举失败处理
在 Redis 哨兵模式中,主节点选举失败通常指在故障转移过程里,领头哨兵未能成功选出合适的新主节点,或者选出新主节点后,故障转移操作未顺利完成。可能的处理方式如下:

  1. 重试选举
    当选举失败,领头哨兵会在一定时间后重新发起选举流程。因为选举失败可能是网络波动、临时节点故障等偶然因素导致,重试可能会成功。例如,从节点网络短暂中断,导致投票未成功,网络恢复后重试就可能正常完成选举。

  2. 人工干预
    如果多次重试选举仍然失败,系统会持续处于不可用状态,此时就需要人工介入排查问题。运维人员会检查网络连接、节点状态、配置文件等,找出选举失败的原因并解决,比如检查从节点是否正常运行、配置参数是否正确等。

  3. 服务不可用
    在选举失败且未解决问题之前,原主节点故障的情况下,服务会持续不可用。客户端对故障主节点负责的数据读写操作会失败,直到选举成功或人工修复问题。

Redis 集群模式选举失败处理
在 Redis 集群模式下,从节点发起的选举若失败,即从节点未能获得足够多主节点的投票成为新主节点,会有以下处理方式:

  1. 等待下一个配置纪元重试
    Redis 集群选举基于配置纪元(Epoch),每个配置纪元内每个主节点只能投一票。选举失败后,从节点会等待下一个配置纪元到来,重新发起选举。新的配置纪元会让主节点重新获得投票权,从节点有机会再次争取选票。

  2. 集群部分不可用
    如果某个主节点下线且其从节点选举失败,该主节点负责的槽位会处于不可用状态。客户端对这些槽位的读写请求会失败,不过集群其他正常节点仍能处理各自负责槽位的请求。

  3. 人工干预恢复
    若选举一直失败,集群部分功能持续不可用,运维人员需要介入。可以通过检查节点状态、网络状况、集群配置等,修复问题。例如,若某个主节点因网络问题无法正常参与投票,可修复网络让其恢复正常,之后重新尝试选举。

  4. 强制故障转移
    在某些情况下,运维人员可以使用 CLUSTER FAILOVER 命令强制从节点进行故障转移,跳过正常选举流程。不过这种方式有数据丢失风险,一般在紧急情况下使用。


文章作者: djaigo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 djaigo !
评论
  目录