持久化
Redis 是内存数据库,为了避免因故障(如服务器重启、断电等)导致数据丢失,提供了多种数据持久化机制,下面详细介绍常见的持久化方式。
RDB(Redis Database)持久化
RDB 是 Redis 默认的持久化方式,它将某一时刻 Redis 内存中的数据生成二进制快照保存到磁盘。
工作原理
- 手动触发:使用
SAVE或BGSAVE命令。SAVE会阻塞 Redis 主线程,直到快照生成完成;BGSAVE则会派生出一个子进程来创建快照,主线程继续处理请求。 - 自动触发:通过配置文件
redis.conf中的save参数设置触发条件,例如save 900 1表示 900 秒内若有 1 个键发生变化,就生成快照。
配置示例
1 | save 900 1 |
优点
- 文件紧凑:RDB 文件是二进制文件,体积小,适合备份和灾难恢复。
- 恢复速度快:加载 RDB 文件到内存时,直接解析二进制数据,速度比 AOF 快。
缺点
- 数据易丢失:若在两次快照之间发生故障,会丢失这期间的数据。
- 阻塞风险:
SAVE命令会阻塞主线程,BGSAVE创建子进程也会有一定性能开销。
AOF(Append Only File)持久化
AOF 持久化是将 Redis 执行的写命令追加到日志文件,以记录数据变化。
工作原理
- Redis 执行写命令时,先将命令写入 AOF 缓冲区,再根据配置策略将缓冲区内容同步到磁盘。
- 有三种同步策略:
always:每次写操作都同步到磁盘,数据安全性最高,但性能最差。everysec:每秒同步一次,兼顾性能和数据安全,是默认配置。no:由操作系统决定何时同步,性能最好,但数据安全性最低。
配置示例
1 | appendonly yes |
优点
- 数据安全:能最大程度减少数据丢失,
always策略几乎不丢失数据。 - 易读可修改:AOF 文件是文本文件,可直接查看和修改。
缺点
- 文件体积大:AOF 文件记录写命令,体积通常比 RDB 文件大。
- 恢复速度慢:恢复数据时需重新执行 AOF 文件中的命令,耗时较长。
混合持久化
Redis 4.0 引入混合持久化,结合了 RDB 和 AOF 的优点。
工作原理
- 执行 AOF 重写时,先将当前内存数据以 RDB 格式写入 AOF 文件,再将重写后的 AOF 日志追加到文件末尾。
配置示例
1 | 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 | port 6379 |
从节点配置 redis.conf:
1 | port 6380 |
2. 配置哨兵节点
创建 sentinel.conf 文件:
1 | port 26379 |
3. 启动哨兵节点
1 | 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 | port 7000 |
其他节点只需修改 port 和 cluster-config-file 中的端口号。
2. 启动节点
分别启动 6 个 Redis 节点:
1 | redis-server redis-7000.conf |
3. 创建集群
使用 redis-cli 创建集群,指定主从关系:
1 | 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 INFO 和 CLUSTER NODES 命令查看集群信息:
1 | redis-cli -c -p 7000 |
优点
- 高可用性:每个主节点有从节点备份,主节点故障时自动故障转移,保障服务不中断。
- 可扩展性:可方便地添加或移除节点,动态调整集群容量。
- 高性能:数据分片存储,多个节点并行处理请求,提升系统吞吐量。
缺点
- 管理复杂度:集群部署和管理相对复杂,需要维护多个节点和它们之间的关系。
- 客户端支持:部分客户端需要支持集群模式,否则需要额外处理重定向等问题。
- 数据一致性:由于采用异步复制,在故障转移时可能存在少量数据丢失。
主节点选举
在 Redis 中有两种常见场景涉及主节点选举,分别是 Redis 哨兵(Sentinel)模式和 Redis 集群模式,下面为你详细介绍这两种模式下主节点选举的机制。
Redis 哨兵(Sentinel)模式主节点选举
在 Redis 哨兵模式中,当主节点出现故障时,哨兵集群会共同协作完成故障转移,从从节点中选举出新的主节点。其选举流程如下:
1. 主观下线与客观下线
- 主观下线(SDOWN):单个哨兵节点通过向 Redis 主节点发送
PING命令,若在指定时间(由down-after-milliseconds配置)内未收到有效回复,该哨兵会将主节点标记为“主观下线”。 - 客观下线(ODOWN):当认为主节点主观下线的哨兵数量达到配置的
quorum值时,该主节点会被判定为“客观下线”,此时触发故障转移流程。
2. 选举领头哨兵
多个哨兵节点需要选举出一个领头哨兵来执行故障转移操作,选举过程基于 Raft 算法的领导者选举机制:
- 每个哨兵节点有一个选举超时时间,当该时间到达时,节点会发起选举,将自己的选举次数加 1,并向其他哨兵节点发送请求投票的消息。
- 其他哨兵节点收到请求后,若还未投票给其他节点,则会回复同意投票,若已经投票则拒绝。
- 当某个哨兵节点收到超过半数哨兵节点的同意投票时,该节点成为领头哨兵。
3. 选择新主节点
领头哨兵从原主节点的从节点中选择一个作为新的主节点,选择规则如下:
- 排除不健康的从节点:排除处于主观下线、客观下线、断线或与原主节点失联时间过长的从节点。
- 选择优先级高的从节点:根据从节点的
slave-priority配置,值越小优先级越高。若slave-priority为 0,则该从节点不会被选为新主节点。 - 选择复制偏移量大的从节点:若优先级相同,则选择复制偏移量最大(即与原主节点数据最接近)的从节点。
- 选择运行 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 哨兵模式中,主节点选举失败通常指在故障转移过程里,领头哨兵未能成功选出合适的新主节点,或者选出新主节点后,故障转移操作未顺利完成。可能的处理方式如下:
重试选举
当选举失败,领头哨兵会在一定时间后重新发起选举流程。因为选举失败可能是网络波动、临时节点故障等偶然因素导致,重试可能会成功。例如,从节点网络短暂中断,导致投票未成功,网络恢复后重试就可能正常完成选举。人工干预
如果多次重试选举仍然失败,系统会持续处于不可用状态,此时就需要人工介入排查问题。运维人员会检查网络连接、节点状态、配置文件等,找出选举失败的原因并解决,比如检查从节点是否正常运行、配置参数是否正确等。服务不可用
在选举失败且未解决问题之前,原主节点故障的情况下,服务会持续不可用。客户端对故障主节点负责的数据读写操作会失败,直到选举成功或人工修复问题。
Redis 集群模式选举失败处理
在 Redis 集群模式下,从节点发起的选举若失败,即从节点未能获得足够多主节点的投票成为新主节点,会有以下处理方式:
等待下一个配置纪元重试
Redis 集群选举基于配置纪元(Epoch),每个配置纪元内每个主节点只能投一票。选举失败后,从节点会等待下一个配置纪元到来,重新发起选举。新的配置纪元会让主节点重新获得投票权,从节点有机会再次争取选票。集群部分不可用
如果某个主节点下线且其从节点选举失败,该主节点负责的槽位会处于不可用状态。客户端对这些槽位的读写请求会失败,不过集群其他正常节点仍能处理各自负责槽位的请求。人工干预恢复
若选举一直失败,集群部分功能持续不可用,运维人员需要介入。可以通过检查节点状态、网络状况、集群配置等,修复问题。例如,若某个主节点因网络问题无法正常参与投票,可修复网络让其恢复正常,之后重新尝试选举。强制故障转移
在某些情况下,运维人员可以使用 CLUSTER FAILOVER 命令强制从节点进行故障转移,跳过正常选举流程。不过这种方式有数据丢失风险,一般在紧急情况下使用。