Redis的主从复制
主从复制的作用
我们在刚开时使用Redis时都是单机测试的,但是生产环境中却不是这样子的,如果我们生产环境中单机部署了,就会遇到下面问题。
- 1 机器故障:如果机器故障了,我们Redis是不是直接就挂了,数据将会丢失。
- 2 容量瓶颈:如果Redis容量满了的话,Redis也是相当于挂了。
这时Redis给我们提供了一种主从复制的机制,我们可以部署多个Redis,这多个Redis共享同样的数据,这样就算一个Redis挂了,我们还有多台备份。
下面给出一个示例来表明这个关系。
可以看到 master 是我们的主节点,slave 是从节点。我们在主节点执行上面两条命令,从节点去获取同样能获取得到数据。当然这里一个master可以有多个从节点,slave也可以有自己的从节点且同时共享一份数据。
这里需要注意的是:
一个master节点可以有多个slave
一个slave只能有一个master
数据流是单项的,只能从master到slave(数据拷贝)
如何实现
-
1使用命令实现
slaveof 命令:
上图意思是 从节点6380
客户端向节点6379
发起成为从节点的请求,之后从节点就会向节点6379
发起文件拷贝。
如果之后从节点要脱离主节点则可以使用slaveof no one
在从节点断开之后原来从主节点复制过来的数据不会立刻得到清除,而是等到该从节点从新绑定主节点的时候才会进行一次清除。 -
2 修改配置
slaveof ip port
#ip
和port
是需要绑定主节点的ip地址和端口
slave-read-only yes
#设置从节点是只读的
这里设置从节点只读的目的是确保数据的一致性,因为数据是单向的,如果从节点插入数据了,那么主节点就不会知道。 -
3 两者比较
方式 使用命令 使用配置 优点 无需重启 统一配置 缺点 不便于管理 需要重启
全量复制和部分复制
这里先介绍变量
run_id
:每个Redis在启动时都会有一个这样的id,我们的主从复制依赖与这个标实,当Redis重启时run_id
会改变。
master-repl-offset
:这个表示现在数据的偏移量,主从通过这个值是否相同来了解数据是否同步。
全量复制
在节点最开始进行从节点申请时就会默认执行一次全量复制。我们知道复制时从节点还不知道主节点的run_id
,这时从节点会发出psync ? -1
的命令去获取主节点的run_id
,获取到之后就开始执行复制。具体的过程看下图。
psync ? -1 # ? 的意思是我第一次获取同步不知道
run_id
多少 -1是我当前文件偏移量
解释下过程
- 1 上面说了
- 2 主节点发送
run_id
和偏移量给从节点。 - 3 从节点保存主节点的信息。
- 4 主节点开始异步RDB文件生成。(上章说明RDB文件的隐式触发)
- 5 主节点发送RDB文件。
- 6 在传送RDB文件时,可能还有数据记录,这时主节点会把记录存在
repl_back_buffer
中,后面在发送一次。 - 7 从节点这时开始清除以前的数据,拥抱新主。
- 8 加载RDB文件。
我们来分析下全量复制的开销
- 1
bgsave
时间,我们上一章节说了生成RDB文件是很消耗资源的。 - 2 RDB文件的网络传输时间:RDB文件是很大的,这将占用很大一部分网络资源
- 3 从节点清除数据时间:如果从节点上一个主的数据太多(很正常),这就要等待清除了。
- 4 从节点加载RDB文件。
- 5 在加载RDB文件后可能会执行AOF从写。
部分复制
我们知道全量复制的开销是很大的,如果有一种情况就是从节点和主节点因为网络关系断开了,这时从节点丢失了主节点的数据,那么我们还要进行一次全量复制吗?这就是部分复制出现的目的,在一些情况中把开销降到最低。
我们看看原理图
解释下流程
- 1 连接断开。
- 2 主节点继续接收数据,并把数据存到
repl_back_buffer
。 - 3 当恢复时从节点请求从新连接主节点。
- 4 连上之后从节点会发送此时的偏移量和
run_id
。 - 5 如果从节点和主节点偏移量的相差返回在
repl_back_buffer
之内,主节点将会执行第6步,如果超出这个范围,很遗憾就只能做全量复制了。 - 6 主节点将缓存数据发送给从节点。
最后
文章开头讲了如何确保数据能够备份,但是出现问题如果我们手动去执行命令的话还是相当麻烦的。不过Redis也提供了一个机制帮我们去解决,就是当我们一个Redis发送故障了,它就会帮我们用其他的Redis顶上,这样少了手动操作的麻烦,又确保数据完整,是不是很棒,这就是我们下章学习的sentinel
。