文章摘要(AI生成)
REDIS持久化有三种方式:RDB持久化、AOF持久化和混合持久化。RDB持久化是Redis 5.0之前默认的持久化方式,通过配置快照规则来触发持久化操作。其优点是可以最大化Redis性能,但缺点是一旦Redis异常退出会丢失最后一次快照以后更改的数据。AOF持久化是通过将每条更改数据的命令写入AOF文件来实现,可以通过配置规则来决定写入时机,但会降低Redis性能。AOF重写是对AOF文件进行压缩,去除重复操作,减小文件体积。如何选择RDB和AOF取决于业务需求,如果数据不能丢失则需要使用RDB+AOF方式持久化,如果只是缓存服务器则只需要配置RDB混合持久化。Redis 5.0之后默认采用混合持久化方式。
REDIS持久化
reids持久化有三种方式
- RDB持久化
- AOF持久化
- 混合持久化
RDB持久化(数据快照)
RDB持久化redis 5.0之前默认的持久化方式,在配置文件中配置快照规则save <time:s> <nums:change_keys>
则表示在多少秒内至少多少个键被更改才触发持久化。
RDB持久化过程:
- 由Redis主进程调用系统中的 fork 函数复制一份子进程的副本
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时(RDB)文件。
- 当子进程写入完所有数据后会用新生成的RDB文件替换旧的 RDB 文件,至此,一次快照操作完成。
RDB的缺点:一旦Redis异常退出,则会丢失最后一次快照以后更改的数据
RDB的优点:由于RDB文件的生成是由子进程操作的,所以可以最大化redis性能。但是数据量较大时,耗时变长的fork会造成服务器暂停处理客户端的请求。
AOF持久化(命令快照)
Redis默认没有开启AOF(append only file)方式的持久化。在配置文件中可以通过配置appendonly yes
开启AOF持久化。开启AOF持久化后,每执行一条会更改 Redis 中的数据的命令, Redis就会将该命令写入硬盘中的 AOF文件硬盘缓存,这一过程显然会降低 Redis 的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。
而由硬盘缓存写入AOF文件(类比记事本编辑文档),则可以通过配置规则appendfsync
决定写入时机,分别为always
-每次写入都会同步,everysec
-每秒写入,no
-操作系统自动写入(会丢失)
AOF重写原理:Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写。重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。例如对一个key的值重复操作时,只保留最新一次操作或合并后的操作即可。
如何选择RDB和AOF?
如果业务场景将Redis用作内存数据库使用,数据不能丢失,则需要使用RDB+AOF方式持久化,如果业务只用做缓存服务器,则只需要配置RDB
混合持久化(数据+命令快照)
redis 5.0之后默认的持久化方式。RDB可能会导致一定时间内的数据丢失,而AOF文件较大则会影响 Redis 的启动速度,为了能同时拥有RDB和AOF的优点,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前 的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能降低数据丢失的风险。
集群演变
数据存储这类应用,需要考虑的问题有两方面:如何防止服务宕机和如何进行服务扩容
数据容灾-哨兵
在防止Redis节点宕机和数据丢失方面,Redis通过主从复制保证了集群备份,并且通过哨兵机制进行主从切换,保证服务的高可用。
主从复制
通过在redis从库上配置slaveof ip port
或replicaof ip port
, 便能开启主从复制。是否全量同步的判断为:
- 只要从机第一次连接上主机是全量同步。
- 断线重连时如果从库的
runid
一致,则为增量同步,否则为全量同步 - 其他场景都为增量同步
全量同步时,会首先同步快照,再同步主节点缓冲区的写操作命令,最后进行增量同步
增量同步时,主节点没执行一个写命令就会发送给从节点,由从节点接收执行
哨兵机制
正常场景下主节点宕机后,我们需要将修改从库配置将从库切换为主库,然后再主库启动后,把启动后的主库修改配置更新为从库。所以我们可以通过一个服务来动态监听主库和从库的状态,来完成主库宕机时的主从切换。
哨兵的工作流程如下:
- 定时请求主从节点,监控redis节点状态
- 当请求主节点时未得到及时响应,则认为主观下线。此时会查询其他哨兵对主节点的状态判断
- 如果认为主节点下线的个数超过选举个数(哨兵个数/2+1),则认为主节点客观下线
- 从哨兵中选举leader执行故障转移,选择主节点(主节点选择依照节点优先级,复制偏移量最大,最小
runid
依次判断)并更新节点配置。 - 更新其他从节点配置,使其为新主的从
流程示意图如下:
需要注意的是哨兵sentinel为redis提供的工具,正常会和我们的redis部署在同一机器上。所以我们在部署redis时会经常选择一主两从或多从的方式。一主一从会在宕机后无法选择出哨兵节点而无法执行故障转移
数据扩容-集群
为了解决redis水平扩容的问题,redis提供了集群部署方式,集群的特征如下:
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 节点的失败是通过集群中超过半数的节点检测失效时才生效.
- 客户端与redis节点直连,不需要中间代理。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
redis-cluster
把所有的物理节点映射到[0-16383]slot中的不同区间上,cluster负责维护node<->slot<->value
集群投票
首先判断节点是否失效:集群中所有master参与投票,如果半数以上master节点与其中一个master节点通信超过(cluster-node-timeout)
,认为该master节点挂掉
然后判断集群是否失效:如果集群中任意master挂掉,且当前master没有slave,则集群进入fail状态。也可以理解成集群的[0- 16383]slot映射不完全时进入fail状态。 如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态。
数据路由
客户端与Redis节点直连,不需要中间Proxy层,直接连接任意一个Master节点根据公式HASH_SLOT=CRC16(key) mod 16384
,计算出映射到哪个分片上,然后Redis会去相应 的节点进行操作
主从切换
当集群中节点通过错误检测机制发现某个节点处于fail状态时,会执行主从切换。Redis 还提供了手动切换的方法,即通过执行cluster failover
命令。
自动切换时流程如下
- 从节点先更新自己的状态,将声明自己为主节点。并且将从节点从主节点中移除
- 由于从节点需要切换为主节点,所以将S的同步数据相关信息清除(即不再从主节点同步锁数据)
- 将主节点提供服务的slot都声明到从节点中
- 发送一个
PONG
包,通知集群中其他节点更新状态
手动切换时流程为:
- 该从节点首先向主节点发送一个
mfstart
包。通知主节点从节点开始进行手动切换 - 主节点会阻塞所有客户端指令的执行。之后主节点在周期函数
clusterCron
中发送ping 包时会在包头部分做特殊标记 - 当从节点收到主节点的
ping
包并且检测到特殊标记之后,会从包头中获取主节点的复制偏移量 - 从节点在周期函数
clusterCron
中检测当前处理的复制偏移量与主节点复制偏移量是否相等,当相等时开始执行切换流程 - 切换完成后,主节点会讲阻塞的所有客户端命令通过发送
+MOVED
指令重定向到新的主节点
副本漂移
副本漂移的场景出现在集群中的某个主节点无从节点时,会从其他主节点上取多余的从节点作为该主节点的从节点。
其在定时巡检的周期函数中会做如下判断
-
是否存在单点的主节点,即主节点没有任何一台可用的从节点
-
是否存在有两台及以上可用从节点的主节点
如果以上两个条件都满足,从有最多可用从节点中选择一台从节点执行副本漂移。选择标准为按节点名称从小到大,选择最靠前的一台从节点执行漂移。
节点迁移
节点添加:为redis集群添加节点时分为三步:
- 添加主节点
- 为节点分配slot
- 添加从节点
节点删除:为redis集群删除节点时分为三步:
- 删除从节点
- 清空主节点的slot
- 删除主节点
评论区