Redis持久化与高可用
# Redis持久化
Redis中提供两种模式提供数据持久化,也就是RDB模式和AOF模式,且这两种模式不冲突可以同时使用,在同时使用时Redis启动只会恢复AOF方式的数据到内存中,一般推荐RDB和AOF一起使用。
# RDB持久化
# 介绍
RDB持久化是把当前reids进程的数据,生成快照持久化到磁盘的过程。
在下次启动时,redis就会自动判断是否有快照文件,如果有则将其中的数据重新读回到内存中,但如果RDB快照文件损坏,Redis会拒绝启动并报错。
且Redis默认会对RDB快照文件做压缩处理,压缩处理后文件远远小于内存大小。
# 优缺点
优点
- RDB持久化生成的文件,代表某个时间点上的数据快照,适合用于全量备份等场景,比如每6小时执行bgsave备份,并把RBD文件拷贝到远程机器,用于灾难恢复。
- Redis加载RDB快照文件恢复数据,远远快于AOF的方式。
缺点
- RDB方式数据没办法做到实时持久化 (秒级),因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,执行成本过高。
- 且存在老版本的redis不兼容新版RDB格式的问题,新版本可以用老版本的RDB文件,但老版本不能用新版本的。因为RDB文件使用特定的二进制格式保存,而redis版本演进过程中有多个格式的RDB版本。
# RDB触发配置
触发RDB持久化的方式有两种,手动触发和自动触发。
手动触发
- redis中执行
bgsave
命令,会将数据快照保存到配置的目录下。 - 执行
bgsave
命令时,redis父进程会判断当前是否已经存在正在执行的子进程。如果存在则bgsave
命令直接返回,如果不存在子进程则执行fork
操作创建一个子进程,专门用于生成RDB持久化文件,不会运行主进程正常工作。 - 另外
save
命令也可以触发RDB持久化,但是会在主进程中执行持久化操作,所以会阻塞主进程运行,导致Redis在持久化过程中不可用,所以手动触发时推荐使用bgsave
命令。
自动触发
Redis的配置文件中设置save参数,可有多条save配置。
# 表示900秒后,900秒期间如果有1次key变化则触发 save 900 1 # 表示300秒后,300秒期间如果有10次key变化则触发 save 300 10 # 表示60秒后,60秒期间如果有10000次key变化则触发 save 60 10000
1
2
3
4
5
6另外在执行SHUTDOWN命令时,默认会自动执行bgsave命令,然后才会关闭Redis。
# AOF持久化
# 介绍
AOF持久化会以独立日志的方式,记录每次的写命令,重启会再读取并执行AOF文件中的命令。
类似于mysql的binlog日志,主要解决数据持久化的实时性。优点是安全,每秒写一次,缺点是恢复数据时没有RDB快。
# 工作过程
命令写入(append) - 在Redis客户端执行写入命令时,Redis会将所有写入命令追加到AOF Buffer中。
刷写缓冲(fsync) - 然后Redis会按AOF持久化策略配置,执行sync指令将AOF Buffer中的数据写入到磁盘中的AOF文件去。
文件重写(rewrite) - 随着AOF文件越来越大,Redis会定期对AOF文件进行重写,以达到压缩的目的。Redis会重写无效的数据,只记录有效的写命令。
例如:
# 客户端执行了添加操作,又执行删除操作,此时a的这两个操作就是无效操作,因为对于最终结果来说a已经不存在了,所以这两个操作重写后不会被记录 >set a 1 >del a 1 # 客户端执行了更新操作,此时a前面两次设置操作就是无效命令,重写后会被删除,只会记录set a 5操作 set a 1 set a 2 set a 5
1
2
3
4
5
6
7
8
Redis重启时,会加载AOF文件进行数据恢复。
# AOF触发重写配置
手动触发
- 执行
bgrewriteaof
命令。
自动触发
配置文件中配置自动触发参数。
auto-aof-rewrite-min-size
- 限制触发AOF文件重写的最小大小,默认64M。- 在AOF文件很小的时候,即使其中有些冗余命令也可是可以忽略的。
auto-aof-rewrite-percentage
- 触发AOF重写的比值,默认100。- 当前的AOF文件大小超过上一次重写的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF大小为依据。
例如:
# 表示当前AOF文件大小是上次重写后文件大小的两倍时,且当前AOF文件大于3GB时触发文件重写 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 3gb
1
2
3
# AOF触发配置
通过配置文件配置。
# 是否启用AOF日志 appendonly yes # 指定AOF日志名 appendfilename "appendonly.aof" # AOF文件磁盘刷写策略,通常选择everysec,在一定程度上兼顾安全性和效率 # no:表示Redis不执行fsync,由文件系统来保证数据刷写到磁盘,速度最快但是不太安全 # always:表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低 # everysec:表示每秒执行一次fsync,但可能会导致丢失一秒内的数据 appendfsync everysec
1
2
3
4
5
6
7
8
9
10
11
# Redis主从复制
# 介绍
主从复制会在多个Redis实例建立主从关系,当主库节点的数据发生变化时,会异步同步给所有从库节点,以此来提供一定的高可用性。一个主库可以拥有多个从库,而一个从库只能拥有一个主库。
主从复制的缺点是没有自动故障转移功能,且无法做到写操作的负载均衡,存储能力受到主Redis节点的限制。所以就有了基于主从复制的哨兵模式和集群模式,哨兵模式和集群模式在主从复制的基础上提供了更多的高可用功能。
# 主从复制的作用
- 数据冗余:可以用作Redis数据的多机热备,可以预防主节点磁盘故障导致的数据文件丢失,因为从库中也会保存数据文件副本。
- 读写分离:可以用于实现Redis数据库的读写分离,单个主节点用于写操作,多个从节点用于读操作。
- 故障转移:可以在主节点故障时手动将从节点升级为主节点,实现故障转移,通过从节点上手动执行
SLAVEOF no one
命令。
# 主从复制的过程
(1)Slave节点的配置文件中配置主库的IP端口信息,如果Master节点有密码那么Slave节点也要配置密码。
(2)Slave节点启动后,会向Master节点发送一个psync命令,请求建立同步连接。
(3)对于第一次连接的Slave节点Redis会先进行快照同步。Master节点建立同步连接后,会先执行bgsave命令fork一个子进程执行RDB持久化操作,同时使用缓存区记录此后Master节点中执行的所有写命令。
- 如果Master节点同时收到了多个Slave的连接请求,那么Master节点只会进行一次RDB持久化,而不是每次连接都执行一次。
- 如果从建立连接到发送RDB快照文件的时间超过60秒,那么Slave节点就会认为复制失败,我们可以通过修改Slave节点的repl-timeout参数进行调整。
(4)Master节点执行完RDB持久化操作后,就会向所有Slave节点发送RDB快照文件,同时在RDB文件传输期间Master节点也会记录写命令到缓冲区。
- 在复制期间如果内存缓冲区大小超过256MB,或者超过64MB的状态持续时间超过60秒,那么就会停止复制,报错复制失败。可以通过修改Master节点配置"client-output-buffer-limit slave 256MB 64MB 60"进行调整。
- Master节点上还会维护了一个backlog文件,主节点向从节点发送RDB快照时,会将传输情况同步往backlog中写,之后如果传输过程意外中断,那么Master节点就可以从backlog文件中得知哪些数据发送成功、哪些发送失败。然后在Slave节点重新连接后,Master会从失败的地方开始增量同步。也就是说在快照传输过程断开后,由于Slave节点重新连接时并非是第一次连接,所以只会进行增量同步,而不是继续进行快照同步。
(5)Slave节点接收到RDB快照文件后,会用收到的新RDB快照文件覆盖本地的旧RDB快照文件,然后从新RDB快照文件中读取数据到内存。
在同步之前Slave节点会使用旧RDB快照文件中的数据提供服务,同步完成后才会用新的RDB快照提供服务。
如果Master节点或Slave节点开启了AOF,那么在快照同步结束后会立即执行BGREWRITEAOF命令,重写AOF文件。建议在主节点使用AOF+RDB的持久化方式,而从节点只使用RDB持久化。
(6)Slave节点将新RDB快照文件全部加载到内存后,会通知Master节点继续进行增量同步。
(7)Master节点收到增量同步请求后,会将缓冲区中的命令以及后续用户执行的写命令发给Slave节点。
(8)Slave节点收到Master节点发来的写命令后就会进行执行,使得主从数据同步。
# 增量同步续传原理
- 增量同步就是在Slave节点全量同步后,Master节点将全量快照后的所有写命令发送到Slave节点,Slave节点读取并执行同步来的写命令。
- 首先Redis会在Master节点中维护一个
repl_backlog_buffer
缓冲区,Master节点会将所有写命令都记录到repl_backlog_buffer
缓冲区中。 - 然后Master节点使用
master_repl_offset
记录自己写命令的最新位置偏移量,而Slave节点使用slave_repl_offset
记录自己读到的位置偏移量。master在执行写命令后,偏移量则会增加。从库执行同步过来的写指令后,偏移量也会增加。 - 一般来说
master_repl_offset
和slave_repl_offset
之间不应该差距过大,过大说明主从同步的延迟过大。 - 当主从断开重连后,Slave节点会先发送
psync
命令给重新建立同步连接,同时将自己的runID
和slave_repl_offset
发送给Master节点。然后Master节点只需要将master_repl_offset
与slave_repl_offset
之间的命令同步给从库即可。 - 同时Slave节点每秒都会上报自己的offset给Master节点,然后Master节点会保存每个从节点的offset,这样主从节点就能知道互相之间的数据一致性情况。
# 无盘复制功能
主节点在进行快照同步时,会进行大量的磁盘IO操作,对于性能差的磁盘来说,快照同步可能会对系统的负载产生较大影响。
Redis从2.8版开始支持无盘复制功能。Master会直接开启一个Socket,在内存中创建RDB文件,再将RDB快照文件直接从内存发送到Slave节点,不使用磁盘作为中间存储。
配置文件中添加参数进行配置即可,一般会在磁盘空间有限或者磁盘性能差,但是网络状态良好的情况下使用。
# 是否开启无磁盘复制(yes/no),默认是no repl-diskless-sync yes # 等待多少秒后开始复制,可以等待更多slave到同步队列 repl-diskless-sync-delay 5
1
2
3
4
5
# 主从复制配置
Slave节点上配置
# 配置Master节点IP端口信息 replicaof 192.168.10.11 6379 # 配置Master节点的密码(如果Master节点没有配置密码则可以忽略) masterauth 123456 # 配置当前Slave节点的密码 requirepass 123456
1
2
3
4
5
6启动Slave节点的Redis服务
redis-server /data/apps/redis/conf/slave.conf
查看主从状态信息
- 主库或者从库执行
info replication
命令即可。
- 主库或者从库执行