【redis】redis主从复制原理
1、Redis 主从复制分为 4 个阶段:
-
初始化
-
建立连接
-
主从握手
-
数据传输(全量/增量复制)
2、主从复制流程由于是是「从库」发起的,所以重点要看从库的执行流程
3、从库发起复制的方式有 3 个:
-
执行 slaveof / replicaof 命令
-
配置文件配置了主库的 ip port
-
启动实例时指定了主库的 ip port
4、建议从 slaveof / replicaof 命令跟源码进去,来看整个主从复制的流程(入口在 replication.c 的 replicaofCommand 函数)
5、从库执行这个命令后,会先在 server 结构体上,记录主库的 ip port,然后把 server.repl_state 从 REPL_STATE_NONE 改为 REPL_STATE_CONNECT,「复制状态机」启动
6、随后从库会在定时任务(server.c 的 serverCron 函数)中会检测 server.repl_state 的状态,然后向主库发起复制请求(replication.c 的 replicationCron 函数),进入复制流程(replication.c 的 connectWithMaster 函数)
7、从库会与主库建立连接(REPL_STATE_CONNECTING),注册读事件(syncWithMaster 函数),之后主从进入握手认证阶段,从库会告知主库自己的 ip port 等信息,在这期间会流转多个状态(server.h 中定义的复制状态):
#define REPL_STATE_RECEIVE_PONG 3 /* Wait for PING reply */
#define REPL_STATE_SEND_AUTH 4 /* Send AUTH to master */
#define REPL_STATE_RECEIVE_AUTH 5 /* Wait for AUTH reply */
#define REPL_STATE_SEND_PORT 6 /* Send REPLCONF listening-port */
#define REPL_STATE_RECEIVE_PORT 7 /* Wait for REPLCONF reply */
#define REPL_STATE_SEND_IP 8 /* Send REPLCONF ip-address */
#define REPL_STATE_RECEIVE_IP 9 /* Wait for REPLCONF reply */
#define REPL_STATE_SEND_CAPA 10 /* Send REPLCONF capa */
#define REPL_STATE_RECEIVE_CAPA 11 /* Wait for REPLCONF reply */
8、完成握手后,从库向主库发送 PSYNC 命令和自己的 offset,首先尝试「增量同步」,如果 offset = -1,主库返回 FULLRESYNC 表示「全量同步」数据,否则返回 CONTINUE 增量同步
9、如果是全量同步,主库会先生成 RDB,从库等待,主库完成 RDB 后发给从库,从库接收 RDB,然后清空实例数据,加载 RDB,之后读取主库发来的「增量」数据
10、如果是增量同步,从库只需接收主库传来的增量数据即可
当一个实例是主库时,为什么不需要使用状态机来实现主库在主从复制时的流程流转?
因为复制数据的发起方是从库,从库要求复制数据会经历多个阶段(发起连接、握手认证、请求数据),而主库只需要「被动」接收从库的请求,根据需要「响应数据」即可完成整个流程,所以主库不需要状态机流转。
redis主从复制,从节点如何决定自己是要做全量同步还是增量同步?
从节点在刚连接主节点时,会发送SYNC命令来请求全量同步。主节点会在后台生成一份RDB快照文件,发送给从节点。从节点接收到快照文件后,会将其存储到本地磁盘上,并且将快照文件中的所有命令重新执行一遍,以保证数据的一致性。
在全量同步完成后,从节点会进入增量同步模式。从节点会发送PSYNC命令来请求增量同步。主节点会记录从节点接收到的最后一条命令的偏移量,并将其发送给从节点。从节点将该偏移量作为自己的复制偏移量,然后开始接收主节点发送的新命令。从节点接收到新命令后,会将其执行一遍,并将自己的复制偏移量更新到最新的值。
因此,从节点不需要决定自己是要做全量同步还是增量同步,而是由主节点来决定。从节点只需要根据主节点发送的指令来执行同步操作即可。
SYNC 和 PSYNC 的区别是什么?
SYNC和PSYNC都是Redis主从复制中用于同步数据的命令,它们的区别如下:
-
SYNC是全量同步,而PSYNC是增量同步。
-
当从节点第一次连接主节点时,会使用SYNC命令进行全量同步。而当从节点在断线后重新连接主节点时,会使用PSYNC命令进行增量同步。
-
SYNC命令会让主节点生成一份RDB快照文件,并将其发送给从节点。从节点接收到快照文件后,会将其存储到本地磁盘上,并且将快照文件中的所有命令重新执行一遍,以保证数据的一致性。而PSYNC命令会让主节点记录从节点接收到的最后一条命令的偏移量,并将其发送给从节点。从节点将该偏移量作为自己的复制偏移量,然后开始接收主节点发送的新命令。
-
在SYNC命令中,主节点会将所有命令发送给从节点,因此可以保证数据的完全一致性。但是全量同步可能会耗费较长时间,如果数据量较大的话,可能会导致从节点长时间处于不可用状态。而在PSYNC命令中,主节点只会发送从指定偏移量之后的命令,因此可以减少同步所需的时间,但是增量同步可能会因为网络等原因丢失一些数据,从而导致数据不一致。
综上所述,SYNC适用于从节点第一次连接主节点或者从节点需要进行全量同步的情况,而PSYNC适用于从节点在断线后重新连接主节点或者从节点需要进行增量同步的情况。
redis主从本来运行ok,但是从节点突然宕了,一段时间再启动,此时从节点应该做什么同步?
如果从节点宕机一段时间后再启动,此时应该进行全量同步。
因为从节点在宕机期间无法接收到主节点发送的增量同步命令,可能会导致从节点数据与主节点数据不一致。因此需要进行全量同步以保证数据的一致性。
从节点启动后,会向主节点发送SYNC命令,请求进行全量同步。主节点会生成一份RDB快照文件,并将其发送给从节点。从节点接收到快照文件后,会将其存储到本地磁盘上,并且将快照文件中的所有命令重新执行一遍,以保证数据的一致性。
需要注意的是,全量同步可能会耗费较长时间,如果数据量较大的话,可能会导致从节点长时间处于不可用状态。
因此,可以考虑在从节点启动前,先将主节点的数据拷贝到从节点上,或者使用AOF持久化方式来避免全量同步带来的影响。
如果杀掉从节点进程然后立刻启动,那么此时从节点做什么同步?
如果杀掉从节点进程然后立刻启动,此时从节点会尝试使用增量同步的方式来进行同步。
从节点启动后,会向主节点发送PSYNC命令,请求进行增量同步。
主节点会记录从节点接收到的最后一条命令的偏移量,并将其发送给从节点。从节点将该偏移量作为自己的复制偏移量,然后开始接收主节点发送的新命令。从节点接收到新命令后,会将其执行一遍,并将自己的复制偏移量更新到最新的值。
需要注意的是,如果从节点在杀掉进程前有未持久化的数据(例如使用了默认的RDB持久化方式),那么这部分数据是无法恢复的。因此,建议在生产环境中使用AOF持久化方式,以确保数据的可靠性。
redis 主从都有做rdb持久化,突然从节点宕机,一段时间后再启动从节点,此时从节点做什么同步?
当从节点宕机后,重新启动时,会先连接主节点并发送SYNC命令,请求主节点将从节点丢失的数据同步过来。
主节点会检查从节点的复制偏移量(replication offset),并将从节点丢失的数据发送给从节点,使其能够恢复到最新的状态。
如果主节点的数据比从节点更老,则从节点需要全量复制主节点的数据。
在同步完成后,从节点会继续接收主节点发来的增量数据,并保持与主节点的数据同步。
主节点的数据比从节点更老 怎么理解?
在 Redis 主从复制中,主节点会将自己的数据同步给从节点,从节点会在主节点的基础上进行增量同步。
如果从节点宕机并且数据持久化方式为 RDB,那么在重新启动时,会先连接主节点并发送 SYNC 命令,请求主节点将从节点丢失的数据同步过来。当主节点的数据比从节点更老时,这意味着从节点宕机前主节点的数据已经发生了变化,而这些变化还没有同步到从节点。因此,从节点需要进行全量复制主节点的数据,以保证数据的一致性。