概述
复制即主从(master-replica),读写分离。
运行机制:
1、主副本连接良好的情况下,主节点会把所有改动通过发送命令流的方式同步到副本节点。
包括客户端写,key过期或者淘汰,和其他在主节点的改动。
2、连接出现问题时,副本节点会尝试重新连接,并且会尝试重新同步连接异常期间丢失的数据。
3、如果同步丢失的数据失败,副本会要求同步完整数据,这个就需要主节点快照整个数据集,再发送到副本节点,之后才会接着正常同步。
默认使用低延时高性能的异步复制模式,适用于大多数Redis用例。副本实例会用异步ACK的方式把自己收到的数据量通告给主节点,所以主节点不需要等待副本节点执行完命令。
客户端可以用WAIT
命令请求对数据进行同步复制,但是WAIT
只能确认指定数量的ACK确认复制。
关于redis复制的说明:
1、redis使用异步复制(也可以同步复制),副主(replica-to-master)之间会异步确认(ack)处理的数据量。
2、一个主可以有多个副。
3、副本节点可以接受其他副本节点的连接。
4、复制在master端是非阻塞的,就是副本节点在进行初始同步或者部分同步的时候,master可以同时处理请求。
5、复制在副本端基本上也是非阻塞的。执行初始同步时,可以用旧数据处理查询,这个需要配置。 当初始同步完成,删除旧数据,载入新数据的这个短暂的时间窗口,将会阻塞进入的连接。 redis4.0开始,可以配置删除旧数据集的操作在另一个线程执行,载入新数据的操作还是会在主线程执行并发生阻塞。
6、复制同时可以用于提供可伸缩性,给只读查询提供多个副本,或者提升数据安全和高可用。
7、还可以利用复制来避免master持久化数据到磁盘的开销。配置master不持久化数据到磁盘,然后连接一个配置了不定期保存或者开启了AOF的副本,但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。
master关闭了持久化下的复制安全
在使用 Redis 复制功能时的设置中,强烈建议在 master 和在 slave 中启用持久化。
没有持久化的情况下,应该避免重启实例后自动启动,否则如果master故障重启了,将会清空所有主副数据。
比如下面的情况:
1、A主节点,主节点关闭了持久化,B和C副本节点
2、A节点崩溃了,然而A有自动重启系统,重启了进程。因为没有开持久化,重启后就是空的数据。
3、B和C从A复制数据,因为A是空的数据,所以副本节点的数据也会被清空。
主节点没有开启持久化的情况下,实例自动重启应该被禁用。
复制是如何工作的
master有个复制ID:大的随机字符串,用来标记数据集。
master持有一个偏移量,会随着发送复制流数据到副本的过程而递增。没有副本节点连接,复制偏移量也会递增,所以复制ID和偏移是成对出现的,Replication ID, offset
用来标识master数据集的版本。
当副本节点连接到master时,用PSYNC
命令来发送旧的master复制ID和已处理的偏移,这样master就只需要发送数据的增量部分到副本。当master缓冲没有积压足够的命令,或者副本用了一个未知的历史复制ID,那么会发生全量数据同步。
全量同步的细节:
master开启一个后台进程,持久化数据为一个RDB文件,同时缓冲新的写入命令,保存数据完成后,传输数据到副本,副本节点载入保存到磁盘的数据到内存。然后master发送(命令流)所有缓冲命令给副本。
复制ID(Replication ID)解释
两个具有相同复制ID和偏移量的实例具有相同的数据。实际是有两个复制ID的,一个主ID,一个辅助ID。
一个复制ID标记了数据集的特定历史记录。
每次一个实例作为master从故障中重新启动,或者副本提升为master,新的复制ID将会生成。副本连接到master之后会继承复制ID,所以两个具有相同ID的实例和持有相同数据是相关的,但是可能是在不同的时间里面。对于给定的历史(复制ID),谁持有最新的数据集,它的偏移量是作为逻辑时间来理解的。
假如有两个实例A和B,他们有相同的复制ID,但是一个偏移是1000,另一个偏移是1023。这意味着第一个缺少一些需要在数据集上执行的命令,也就是A只需要执行少量的命令,就可以达到和B一样的状态。
redis实例有两个复制ID的原因是副本可以提升为master。当发生故障转移后,副本提升仍然需要记住它过去的复制ID,因为这个复制ID是前任master之一。当其他副本从新master同步数据时,他们会用旧master的复制ID来执行部分数据再同步。当副本提升为master时,它会设置自己的辅助ID为主ID,同时记住发生ID切换时的偏移量。之后它会生成新的复制ID,因为开始了一个新的历史。 当处理新副本连接时,master会以他们的ID和偏移匹配当前ID和辅助ID(到达给定的偏移量),简单的说就是,发生故障转移后,副本会连接到新的master,而且不会发生全量同步。
为什么故障转移后,要改变副本ID?因为网络分区,旧的master可能仍然在作为master在运行。 保留相同的ID会违反任意两个具有相同ID和偏移的实例,持有相同数据的规则。
配置
要配置基本的redis复制功能,仅需在副本节点添加如下配置:
replicaof 192.168.1.1 6379
192.168.1.1
:master IP
6379
:master端口
或者在副本节点执行REPLICAOF
命令手动启动复制。
redis 2.8.18开始支持无磁盘复制,直接发送RDB文件给副本节点,不需要保存到磁盘再发送。
repl-diskless-sync
:1 开启无盘复制
repl-diskless-sync-delay
:秒,延迟传输,目的可以在第一个副本就绪后,等待更多的副本就绪
只读副本
redis 2.6开始,副本支持只读模式,并且是默认开启。
通过配置选项replica-read-only
控制。
设置副本的master安全验证
如果master通过requirepass
设置了密码,副本节点则需要设置使用这个密码。
修改配置文件:
masterauth <password>
只允许有N个副本的写入
redis2.8开始,支持配置master至少有N个副本时才接受写查询。
两个配置:
min-replicas-to-write <number of replicas>
min-replicas-max-lag <number of seconds>
至少需要min-replicas-to-write
个延时小于等于min-replicas-max-lag
秒的副本节点连接到master,master才会接受写入请求,否则会抛出错误,目的是尽可能避免副本的数据丢失。
复制情况下,key过期的处理方式
1、副本不过期key,而是等待master来过期key,当master一个key过期时或者是被LRU算法淘汰,master会发送一个DEL
命令到所有的副本。
2、因为有时master不能及时的传输DEL
过来,所以副本还是会存在逻辑上已经过期的key。
为了解决这个问题,副本仅在读取操作时使用逻辑时钟来报告key不存在,这样就可以避免一个过期的key仍然存在可读取。
3、Lua脚步执行期间不执行任何key过期操作。
在Docker和NAT配置复制
副本使用ROLE
和INFO
命令的输出传到master,master使用副本传输过来的信息来获取副本的IP地址,在Docker或者NAT环境,获取的这些信息可能和实际是不一样的,端口也可能不一样。
为了解决这个问题,从redis 3.2.2开始,可以配置副本提供给master的IP和端口。
配置选项如下:
replica-announce-ip 5.5.5.5
replica-announce-port 1234
INFO和ROLE命令
这两个命令提供了主副节点关于复制的信息。
INFO
:执行INFO replication
命令仅会现实复制相关的信息ROLE
:提供 master 和 slave 的复制状态以及它们的复制偏移量,连接的副本列表等。
重启和故障转移后的部分同步
4.0版本之后,当一个节点提升为master节点是,它将仍然可以执行和旧master节点的副本节点之间的部分同步。为了做到这点,副本会记住旧的复制ID和偏移,所以当副本节点用旧的复制ID请求同步数据时,仍然可以提供积压的数据。
当副本节点关闭电源和重启之后,可以用存储在RDB
文件的信息来和master重新同步,可以的情况下,使用SHUTDOWN
命令来关闭是更好的选择,因为可以执行save & quit
操作。
副本通过AOF文件重新启动不会进行部分同步,可以在关闭实例之前切换到RDB持久化,然后重启,再启用AOF持久化。
副本的最大内存
副本节点默认会忽略最大内存(maxmemory)设置,key淘汰会由master来执行,再发送DEL
命令同步到副本。
使用配置replica-ignore-maxmemory no
选项配置副本节点不忽略最大内存限制。
根据redis官方文档翻译整理而成,https://redis.io/docs/manual/replication/
本文链接:https://360us.net/article/74.html