redis持久化和主从复制
redis 是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失。幸好 Redis 还为我们提供了持久化的机制,分别是 RDB (Redis DataBase) 和 AOF (Append Only File)。
持久化过程#
客户端向服务端发送写操作 (数据在客户端的内存中)。
数据库服务端接收到写请求的数据 (数据在服务端的内存中)。
服务端调用 write 这个系统调用,将数据往磁盘上写 (数据在系统内存的缓冲区中)。
操作系统将缓冲区中的数据转移到磁盘控制器上 (数据在磁盘缓存中)。
磁盘控制器将数据写到磁盘的物理介质中 (数据真正落到磁盘上)。
这 5 个过程是在理想条件下一个正常的保存流程,但是在大多数情况下,我们的机器等等都会有各种各样的故障,这里划分了两种情况:
Redis 数据库发生故障,只要在上面的第三步执行完毕,那么就可以持久化保存,剩下的两步由操作系统替我们完成。
操作系统发生故障,必须上面 5 步都完成才可以。
RDB 机制#
RDB 其实就是把数据以快照的形式保存在磁盘上。什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。
RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为 dump.rdb。
可以在配置文件中指定文件名和文件路径
在我们安装了 redis 之后,所有的配置都是在 redis.conf 文件中,里面保存了 RDB 和 AOF 两种持久化机制的各种配置。
既然 RDB 机制是通过把某个时刻的所有数据生成一个快照来保存,那么就应该有一种触发机制,是实现这个过程。对于 RDB 来说,提供了三种机制:save、bgsave、自动化。我们分别来看一下
save#
该命令会阻塞当前 Redis 服务器,执行 save 命令期间,Redis 不能处理其他命令,直到 RDB 过程完成为止。具体流程如下:
执行完成时候如果存在老的 RDB 文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。
bgsave#
执行该命令时,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体流程如下:
具体操作是 Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。基本上 Redis 内部所有的 RDB 操作都是采用 bgsave 命令。
自动触发#
①save:这里是用来配置触发 Redis 的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如 “save m n”。表示 m 秒内数据集存在 n 次修改时,自动触发 bgsave。
默认如下配置:
#表示 900 秒内如果至少有 1 个 key 的值变化,则保存 save 900 1
#表示 300 秒内如果至少有 10 个 key 的值变化,则保存 save 300 10
#表示 60 秒内如果至少有 10000 个 key 的值变化,则保存 save 60 10000
不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。
②stop-writes-on-bgsave-error :默认值为 yes。当启用了 RDB 且最后一次后台保存数据失败,Redis 是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果 Redis 重启了,那么又可以重新开始接收数据了
③rdbcompression ;默认值是 yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。
④rdbchecksum :默认值是 yes。在存储快照后,我们还可以让 redis 使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
我们可以修改这些配置来实现我们想要的效果。因为第三种方式是配置的,所以我们对前两种进行一个对比:
RDB 的优势和劣势#
①、优势
(1)RDB 文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
(2)生成 RDB 文件的时候,redis 主进程会 fork () 一个子进程来处理所有保存工作,主进程不需要进行任何磁盘 IO 操作。
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
②、劣势
RDB 快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。
AOF 机制#
全量备份总是耗时的,有时候我们提供一种更加高效的方式 AOF,工作机制很简单,redis 会将每一个收到的写命令都通过 write 函数追加到文件中。通俗的理解就是日志记录。
1、持久化原理
他的原理看下面这张图:
每当有一个写命令过来时,就直接保存在我们的 AOF 文件中。
2、文件重写原理
AOF 的方式也同时带来了另一个问题。持久化文件会变的越来越大。为了压缩 aof 的持久化文件。redis 提供了 bgrewriteaof 命令。将内存中的数据以命令的方式保存到临时文件中,同时会 fork 出一条新进程来将文件重写。
重写 aof 文件的操作,并没有读取旧的 aof 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 aof 文件,这点和快照有点类似。
3、AOF 也有三种触发机制
(1)每修改同步 always:同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好
(2)每秒同步 everysec:异步操作,每秒记录 如果一秒内宕机,有数据丢失
(3)不同 no:从不同步
4.AOF 配置
表示是否开启 AOF 持久化:appendonly yes (默认 no, 关闭)
AOF 持久化配置文件的名称:appendfilename “appendonly.aof”
AOF 持久化策略 (默认每秒):
appendfsync always (同步持久化,每次发生数据变更会被立即记录到磁盘,性能差但数据完整性比较好)
appendfsync everysec (异步操作,每秒记录,如果一秒钟内宕机,有数据丢失)
appendfsync no (将缓存回写的策略交给系统,linux 默认是 30 秒将缓冲区的数据回写硬盘的)
bgrewriteaof 机制,在一个子进程中进行 aof 的重写,从而不阻塞主进程对其余命令的处理,同时解决了 aof 文件过大问题。在执行 bgrewriteaof 操作和主进程写 aof 文件的操作,两者都会操作磁盘,而 bgrewriteaof 往往会涉及大量磁盘操作,这样就会造成主进程在写 aof 文件的时候出现阻塞的情形,现在 no-appendfsync-on-rewrite 参数出场了。如果该参数设置为 no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为 yes 呢?这就相当于将 appendfsync 设置为 no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候 redis 挂掉,就会丢失数据
no-appendfsync-on-rewrite no
Redis 会记录上次重写时的 AOF 文件大小,默认配置时当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发
auto-aof-rewrite-percentage 100 (一倍)
auto-aof-rewrite-min-size 64mb
指 redis 在恢复时,会忽略最后一条可能存在问题的指令。默认值 yes。即在 aof 写入时,可能存在指令写错的问题 (突然断电,写了一半),这种情况下,yes 会 log 并继续,而 no 会直接恢复失败.
aof-load-truncated yes
允许使用 RDB-AOF 混合持久化的方式结合了两者的优点通过 aof-use-rdb-preamble 配置项可以打开混合开关
aof-use-rdb-preamble yes
RDB 的优势和劣势#
①优点
(1)AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次 fsync 操作,最多丢失 1 秒钟的数据。
(2)AOF 日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
(3)AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
(4)AOF 日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用 flushall 命令清空了所有数据,只要这个时候后台 rewrite 还没有发生,那么就可以立即拷贝 AOF 文件,将最后一条 flushall 命令给删了,然后再将该 AOF 文件放回去,就可以通过恢复机制,自动恢复所有数据
②缺点
(1)对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大
(2)AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync 一次日志文件,当然,每秒一次 fsync,性能也还是很高的
(3)以前 AOF 发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。
RDB 和 AOF 到底该如何选择#
redis 主从复制#
和 Mysql 主从复制的原因一样,Redis 虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis 支持主从复制,Redis 的主从结构可以采用一主多从或者级联结构,Redis 主从复制可以根据是否是全量分为全量同步和增量同步。下图为级联结构。
全量同步
Redis 全量复制一般发生在 Slave 初始化阶段,这时 Slave 需要将 Master 上的所有数据都复制一份。具体步骤如下:
- 从服务器连接主服务器,发送 SYNC 命令;
- 主服务器接收到 SYNC 命名后,开始执行 BGSAVE 命令生成 RDB 文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器 BGSAVE 执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。
增量同步
Redis 增量复制是指 Slave 初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
Redis 主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
注意点
如果多个 Slave 断线了,需要重启的时候,因为只要 Slave 启动,就会发送 sync 请求和主机全量同步,当多个同时出现的时候,可能会导致 Master IO 剧增宕机。
主从复制的一些特点:
1)采用异步复制;
2)一个主 redis 可以含有多个从 redis;
3)每个从 redis 可以接收来自其他从 redis 服务器的连接;
4)主从复制对于主 redis 服务器来说是非阻塞的,这意味着当从服务器在进行主从复制同步过程中,主 redis 仍然可以处理外界的访问请求;
5)主从复制对于从 redis 服务器来说也是非阻塞的,这意味着,即使从 redis 在进行主从复制过程中也可以接受外界的查询请求,只不过这时候从 redis 返回的是以前老的数据,如果你不想这样,那么在启动 redis 时,可以在配置文件中进行设置,那么从 redis 在复制同步过程中来自外界的查询请求都会返回错误给客户端;(虽然说主从复制过程中对于从 redis 是非阻塞的,但是当从 redis 从主 redis 同步过来最新的数据后还需要将新数据加载到内存中,在加载到内存的过程中是阻塞的,在这段时间内的请求将会被阻,但是即使对于大数据集,加载到内存的时间也是比较多的);
6)主从复制提高了 redis 服务的扩展性,避免单个 redis 服务器的读写访问压力过大的问题,同时也可以给为数据备份及冗余提供一种解决方案;
7)为了编码主 redis 服务器写磁盘压力带来的开销,可以配置让主 redis 不在将数据持久化到磁盘,而是通过连接让一个配置的从 redis 服务器及时的将相关数据持久化到磁盘,不过这样会存在一个问题,就是主 redis 服务器一旦重启,因为主 redis 服务器数据为空,这时候通过主从同步可能导致从 redis 服务器上的数据也被清空;
实践配置 redis 主从复制#
由于 redis 为单线程模式,所以我们可以在一个服务器上部署多个 redis 服务
复制两个配置文件,其他 6379 和 6380 为两个 redis 使用的端口号
cp redis.conf redis-6379.conf
cp redis.conf redis-6380.conf
修改 redis-6380.conf 中的配置项
修改监听端口 port 6380
修改 pid 运行文件 pidfile /var/run/redis_6380.pid
关闭 rdb 备份#save 900 1
#save 300 10
#save 60 10000
使用命令开启两个 redis 服务./redis-server redis-6379.conf
./redis-server redis-6380.conf
使用命令 ps -ef | grep redis
查看进程状态,表示 6379 和 6380 的 redis 端口状态已开启
从服务器配置
配置 slaveof 项,对应主服务器的 ip 和端口 slaveof 127.0.0.1 6379
如果主服务器有配置密码,需要添加 masterauth + 密码配置项 masterauth xxx
配置完成后重启 redis 服务
查看 6379 端口的 redis,使用 info replication 查看信息
设置一个键值测试
查看 6380 端口的 redis,使用 info replication 查看信息
查看设置的键值
可以查看到从服务器已同步了主服务器数据
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: