Redis复制原理解析

1.概述

redis在目前生产环境都是集群部署,通过哨兵保证集群的高可用。但凡涉及到集群以及存储方面的需求,无法避免的就是数据复制问题。这篇文章主要说一下redis复制原理,以及redis复制需要注意的问题,还有就是业务方应该避免的坑。

2.核心点

建立主从命令slaveof

slaveof no one: 取消现有的主从关系,使slave变成master

slaveof host port:将当前实例变成指定节点的从节点。

主从命令slaveof实现(定时任务驱动)

通过定时任务和主节点建立连接并进行复制前逻辑

定时任务流程:

(1)任务发现存在新的主节点,建立连接

(2)发送ping

(3)鉴权 如果主节点有requirepass。那么从节点需要配置masterauth

(4)同步全量数据

(5)持续发送写命令到从节点

内部数据同步使用psync命令

psync命令响应:
  • +FULLRESYNC:全量复制
  • +CONTINUE 部分复制
  • +ERR 版本太低
全量复制

从节点发送psync-1 进行全量复制

部分复制

通过offset 以及 运行id来实现部分复制,如果主节点的复制积压缓冲区(back_log)存在数据的话。直接返回给从节点可进行部分复制。
这里说一下部分复制依赖的是slave的offset,以及主节点的back_log。主节点的back_log是一个1M大小的环形链表。主节点每次处理命令的时候都会将命令写入back_log。

心跳探活

主节点通过心跳可以判断节点是否存活。
从节点每1s通过replconf ack offset命令上报当前复制的偏移量。

3.原理分析

Redis的slave通过server.repl_state状态来区分当前的复制状态。整个复制流程就是状态转变的过程。

#define REDIS_REPL_NONE 0 /* No active replication */ 没有进行复制

#define REDIS_REPL_CONNECT 1 /* Must connect to master */ 连接

#define REDIS_REPL_CONNECTING 2 /* Connecting to master */ 建立连接
#define REDIS_REPL_RECEIVE_PONG 3 /* Wait for PING reply */ 等待ping
#define REDIS_REPL_TRANSFER 4 /* Receiving .rdb from master */ 传输 rdb
#define REDIS_REPL_CONNECTED 5 /* Connected to master */ 复制完成,进行增量同步

Redis的master通过对应slave客户端的replstate来记录当前客户端的状态

#define REDIS_REPL_WAIT_BGSAVE_START 6 /* We need to produce a new RDB file. */ 客户等待执行rdb
#define REDIS_REPL_WAIT_BGSAVE_END 7 /* Waiting RDB file creation to finish. */ 等待rdb执行完成
#define REDIS_REPL_SEND_BULK 8 /* Sending RDB file to slave. */ 接收rdb中
#define REDIS_REPL_ONLINE 9 /* RDB file transmitted, sending just updates. */ 在线 命令传播

接下来我们对源码进行分析。

slaveofCommand方法

该方法为slaveof命令的命令处理方法。我们主要看一下slaveof host port逻辑。

long port;
if ((getLongFromObjectOrReply(c, c->argv[2], &port, NULL) != REDIS_OK))
    return;
if (server.masterhost && !strcasecmp(server.masterhost,c->argv[1]->ptr)
    && server.masterport == port) {
   
    addReplySds(c,sdsnew("+OK Already connected to specified master\r\n"));
    return;
}
replicationSetMaster(c->argv[1]->ptr, port);

如果指定的host、port已经是当前节点的master,直接返回,否则调用replicationSetMaster去设置master

replicationSetMaster方法

void replicationSetMaster(char *ip, int port) {
   
    // 清除原有的主服务器地址(如果有的话)
    sdsfree(server.masterhost);
    // IP
    server.masterhost = sdsnew(ip);
    // 端口
    server.masterport = port;
    if (server.master) freeClient(server.master);
    disconnectSlaves(); /* Force our slaves to resync with us as well. */
    // 清空可能有的 master 缓存,因为已经不会执行 PSYNC 了
    replicationDiscardCachedMaster(); 
    freeReplicationBacklog(); 
    cancelReplicationHandshake();
    // 进入连接状态
    server.repl_state = REDIS_REPL_CONNECT;
    server.master_repl_offset = 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值