上一章 简述了主从复制的基本配置,以及抓包查看了数据复制的一些工作流程,本章将通过源码去深入分析 redis 主从节点数据复制的要点逻辑:复制命令,master 服务副本 ID,复制偏移量,积压缓冲区。
redis 是纯 c 源码,阅读起来实现比较清晰,缺点:它也是一个异步的网络框架,回调处理的逻辑理解有点费劲。
1. 数据结构
1.1. redisServer
redis master / slave 节点数据结构 redisServer
。
#define CONFIG_RUN_ID_SIZE 40
struct redisServer {
...
list *slaves, *monitors; /* List of slaves and MONITORs */
...
/* Replication (master) */
char replid[CONFIG_RUN_ID_SIZE+1]; /* My current replication ID. */
char replid2[CONFIG_RUN_ID_SIZE+1]; /* replid inherited from master*/
long long master_repl_offset; /* My current replication offset */
long long master_repl_meaningful_offset; /* Offset minus latest PINGs. */
long long second_replid_offset; /* Accept offsets up to this for replid2. */
char *repl_backlog; /* Replication backlog for partial syncs */
long long repl_backlog_size; /* Backlog circular buffer size */
long long repl_backlog_histlen; /* Backlog actual data length */
long long repl_backlog_idx; /* Backlog circular buffer current offset,
that is the next byte will'll write to.*/
long long repl_backlog_off; /* Replication "master offset" of first
...
/* Replication (slave) */
char *masterhost; /* Hostname of master */
int masterport; /* Port of master */
client *master; /* Client that is master for this slave */
client *cached_master; /* Cached master to be reused for PSYNC. */
int repl_state; /* Replication status if the instance is a slave */
...
char master_replid[CONFIG_RUN_ID_SIZE+1]; /* Master PSYNC runid. */
long long master_initial_offset; /* Master PSYNC offset. */
}
- master
结构成员 | 描述 |
---|---|
slaves | slaves副本链接列表。 |
replid | 副本id,只有master有自己独立的replid,如果服务是slave,那么它需要复制master的replid,进行填充。 |
replid2 | master历史replid。复制双方断开链接或者故障转移过程中,服务节点角色发生改变,需要缓存旧的masterreplid到replid2。因为所有slave数据都来自master。复制双方重新建立链接后,通过PSYNC<replid><offset>命令进行数据复制。 |
master_repl_offset | master数据偏移量。复制双方是异步进行的,所以数据并不是严格的数据强一致。 |
second_replid_offset | 历史数据偏移量。与replid2搭配使用。 |
repl_backlog | 积压缓冲区。被设计成环形数据结构(连续内存空间)。 |
repl_backlog_size | 积压缓冲区容量。可以通过配置文件进行配置。 |
repl_backlog_histlen | 积压缓冲区实际填充了多少数据。 |
repl_backlog_idx | 积压缓冲区,当前填充数据的位置。 |
repl_backlog_off | 积压缓冲区数据起始位置。server.repl_backlog_off=server.master_repl_offset+1 |
- slave
结构成员 | 描述 |
---|---|
masterhost | 保存master节点的主机地址。 |
masterport | 保存master节点的端口。 |
repl_state | 副本状态,复制双方建立数据复制要经过很多步骤,而这些步骤被进行到哪个环节被记录在repl_state。(您可以为记录异步通信状态机的当前状态。) |
master | slave链接master的客户端链接。 |
cached_master | slave与master断开链接后,原链接被释放回收。为方便断线重连后数据重复被利用,需要缓存master链接数据到cached_master。 |
master_replid | master的replid。 |
master_initial_offset | slave通过命令PSYNC向master全量复制的数据偏移量。 |
1.2. client
master 与 slave 节点间异步通信链接对象。
typedef struct client {
...
long long read_reploff; /* Read replication offset if this is a master. */
long long reploff; /* Applied replication offset if this is a master. */
char replid[CONFIG_RUN_ID_SIZE+1]; /* Master replication ID (if master). */
...
}
结构成员 | 描述 |
---|---|
replid | master副本id。 |
read_reploff | slave当前向master读取的数据偏移量。 |
masterport | slave当前实际处理的数据偏移量。因为异步复制,有些读数据,读出来没有完全处理完,还在缓冲区里。例如tcp粘包问题,数据没有接收完整,等原因。 |