3.只开启RDB方式的主从复制原理

  1. 首先,以7版本为例,在本机模拟两台redis,为了不影响其他业务的使用,在root下新建一个test目录,将所有redis实例的配置文件复制到test目录中。如:
    [root@localhost test]# cp /etc/redis/* ./
  2. 用vi命令分别为test下配置文件作如下配置,即开启RDB(默认开启的),关闭AOF以及混合模式:
    save 3600 1 300 100 60 10000
    appendonly no
    aof-use-rdb-preamble no
    另外为了方便观察,还可以注释掉日志的记录,让日志能够打印到控制台上:
    # logfile /var/log/redis_6379.log
    还可以把服务方式调整为前台阻塞,这样可以更清晰的看到业务运行过程:
    daemonize no
    :wq命令退出并保存
  3. 进入到test目录下后,开启两台redis-server:
    redis-server 6379.conf
    redis-server 6380.conf
  4. 再开启两个客户端,分别对应着服务的端口:
    redis-cli -p 6379
    redis-cli -p 6380
    在6379的库里分别设置一些数据,如:
127.0.0.1:6379> set k1 aaa
OK
127.0.0.1:6379> set k2 bbb
OK
127.0.0.1:6379> set k3 ccc
OK

此时在6380的库里是肯定看不到的,因为二者还没建立关联。同样的,6380的数据目录下也没有任何内容。

[root@localhost 6380]# ll
总用量 0

此时在6380的客户端执行REPLICAOF 127.0.0.1 6379

127.0.0.1:6380> REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:6380> 

此时,返回OK代表6380作为从,与6379这个主已成功建立主从关系。
这时再看6380里的键:

127.0.0.1:6380> keys *
1) "k1"
2) "k2"
3) "k3"
127.0.0.1:6380> 

数据已经从6379成功同步过来了。再看6380的数据文件夹,发现生成了一个RDB文件。

[root@localhost 6380]# ll
总用量 4
-rw-r--r--. 1 root root 200 12月 26 19:08 dump.rdb
[root@localhost 6380]# 

用vi命令打开这个RDB文件,会发现基本上都是乱码,但是有一些数据是可以看懂的,如:


image.png

这些aaa,bbb,ccc正是刚才在6379里设置的值,说明从已经把主的数据同步过来形成一个RDB文件了。

  1. 接下来分析这个过程如何发生。因为已经设置过服务前台阻塞,并且让前台打印日志,所以我们可以对这些日志作分析。
    在6380从机执行replicaof 127.0.0.1 6379命令后,6380的服务端会大致打印出以下日志(附上简单翻译或分析):
1822:S 26 Dec 2022 13:13:49.247 * Before turning into a replica, using my own master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
在转换为副本之前,使用我自己的主参数来合成缓存的主文件:我可以通过部分传输与新的主文件同步。
1822:S 26 Dec 2022 13:13:49.247 * Connecting to MASTER 127.0.0.1:6379
连接到6379端口的主
1822:S 26 Dec 2022 13:13:49.247 * MASTER <-> REPLICA sync started
“从”开始同步
1822:S 26 Dec 2022 13:13:49.247 * REPLICAOF 127.0.0.1:6379 enabled (user request from 'id=3 addr=127.0.0.1:33098 laddr=127.0.0.1:6380 fd=8 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 ssub=0 multi=-1 qbuf=44 qbuf-free=20430 argv-mem=22 multi-mem=0 rbs=16384 rbp=16384 obl=0 oll=0 omem=0 tot-mem=37678 events=r cmd=replicaof user=default redir=-1 resp=2')
通过一系列的参数可以成功追随到6379
1822:S 26 Dec 2022 13:13:49.247 * Non blocking connect for SYNC fired the event.
同步非阻塞触发事件
1822:S 26 Dec 2022 13:13:49.248 * Master replied to PING, replication can continue...
主请求建立连接,从可以接收到连接
1822:S 26 Dec 2022 13:13:49.248 * Trying a partial resynchronization (request a21aab7153eeee37a33d1447f928f346c2ec21a5:1).
尝试部分的重新同步
1822:S 26 Dec 2022 13:13:54.670 * Full resync from master: d52a77884eec992567f8fbacc0c005d12c669c39:195
从主全部重新同步
1822:S 26 Dec 2022 13:13:54.670 * MASTER <-> REPLICA sync: receiving streamed RDB from master with EOF to disk
从接收到了主的RDB流,并保存到磁盘上
1822:S 26 Dec 2022 13:13:54.671 * Discarding previously cached master state.
舍弃之前主缓存的状态
1822:S 26 Dec 2022 13:13:54.671 * MASTER <-> REPLICA sync: Flushing old data
清除从里旧的数据
1822:S 26 Dec 2022 13:13:54.671 * MASTER <-> REPLICA sync: Loading DB in memory
将数据加载到内存
1822:S 26 Dec 2022 13:13:54.671 * Loading RDB produced by version 7.0.5
加载到内存这个过程用的是7.0.5版本
1822:S 26 Dec 2022 13:13:54.671 * RDB age 0 seconds
1822:S 26 Dec 2022 13:13:54.671 * RDB memory usage when created 0.99 Mb
数据内存消耗0.99M
1822:S 26 Dec 2022 13:13:54.671 * Done loading RDB, keys loaded: 2, keys expired: 0.
加载结束,一共有两个键,没有过期时间
1822:S 26 Dec 2022 13:13:54.671 * MASTER <-> REPLICA sync: Finished with success
主从同步到此完成

6379的服务端会大致打印出以下日志:

1795:M 26 Dec 2022 13:13:49.248 * Replica 127.0.0.1:6380 asks for synchronization
6380端口的从请求同步数据
1795:M 26 Dec 2022 13:13:49.248 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'a21aab7153eeee37a33d1447f928f346c2ec21a5', my replication IDs are 'd52a77884eec992567f8fbacc0c005d12c669c39' and '0000000000000000000000000000000000000000')
1795:M 26 Dec 2022 13:13:49.248 * Delay next BGSAVE for diskless SYNC
未使用磁盘方式去作BGSAVE同步(直接使用网络传输)
1795:M 26 Dec 2022 13:13:54.669 * Starting BGSAVE for SYNC with target: replicas sockets
开始使用BGSAVE命令给从做同步传输
1795:M 26 Dec 2022 13:13:54.669 * Background RDB transfer started by pid 1831
重新启动一个进程1831,做非阻塞的RDB传输
1831:C 26 Dec 2022 13:13:54.670 * Fork CoW for RDB: current 4 MB, peak 4 MB, average 4 MB
为RDB做Fork系统调用,使用Cow写时复制机制,当前文件大小4M,最多4M,平均4M
1795:M 26 Dec 2022 13:13:54.670 # Diskless rdb transfer, done reading from pipe, 1 replicas still up.
无盘模式RDB传输,从管道中读取完成,目前有一个从在等待
1795:M 26 Dec 2022 13:13:54.671 * Background RDB transfer terminated with success
非阻塞RDB成功传输到从
1795:M 26 Dec 2022 13:13:54.671 * Streamed RDB transfer with replica 127.0.0.1:6380 succeeded (socket). Waiting for REPLCONF ACK from slave to enable streaming
RDB文件成功通过网络传输给从,等待从的最终返回结果流
1795:M 26 Dec 2022 13:13:54.671 * Synchronization with replica 127.0.0.1:6380 succeeded
最终成功同步(一定是主接收到了从同步成功的最终返回消息)

一句话总结。这种方式下,从在追随成功之后,主默认通过网络直接发送数据的模式(当然可以在配置文件中进行配置),把数据发送给从,从把这些数据最终形成一个RDB文件,保存到数据文件目录中。

  1. 故障的发生。
    假如从机挂掉以后,主机会第一时间收到消息,日志中打印为:Connection with replica 127.0.0.1:6380 lost
    在从机挂掉这段时间,如果主机中有了新数据,从机恢复以后,再次与主机建立主从关系,从机仍然是可以同步到这些新数据的。(原理可以从以上日志文件看出,从在同步成功主数据后,在加载到内存之前,是要把老的数据都清除的,把所有的数据再重新同步一遍)。

再假设一种情况,在主从关系正常的情况下,如果把6380数据目录下的RDB文件删除,那么6380还可以获得这些键吗?是可以的。还是根据日志的记录可以看出,再主机向从机传输完数据后,从机是会把这些数据加载到内存的。所以仍然可以访问。

那么这时如果主机6379新增了内容,那么6380从机可以直接看到吗?当然可以看到,但是暂时不会生成RDB文件,此时的同步都是发生在内存层面的。还没有到配置文件中save策略所达到的时间或操作笔数。(注意:虽然配置文件中配置的是save,但是触发的是bgsave的操作)。只有达到策略配置的要求,或者是从机第一次与主机建立关系,再或者是发生故障断开后重新连接,才会自动进行全局的数据同步。

发生故障的不一定只有从机,只机也会发生故障。如果主机发生故障了,最常用的方式就是让一台选定的从机顶替上去,作为主机来用。可以手动来操作,但是最常见的是使用程序来监控进行故障转移。具体的下次与AOF或者preamble混合模式结合再进行讨论分析。

你可能感兴趣的:(3.只开启RDB方式的主从复制原理)