目录

目录 1

1. 前言 1

2. 配置项 1

3. redisServer 2

4. feedReplicationBacklog-写repl_backlog 3

5. addReplyReplicationBacklog-读repl_backlog 4

1. 前言

注意,repl_backlog只针对部分复制(Partial Replication),而非全量复制。

本文内容基于redis-5.0.5(截至2019/6/6的最新版本),本文深入介绍REdis主从复制的部分复制核心要素repl_backlog,与其相关的配置直接影响主从间的稳定性,对提升集群的稳定性十分重要。

注意REdis的主节点把所有从节点也当作一个Client看待,正常的数据同步并不涉及repl_backlog。当从节点断开重连,这个时候repl_backlog的作用就体现出来了。截至到5.0.5版本,从节点重启用不上repl_backlog,原因是从节点没有保存repl_backlog的信息,无法实现部分同步,但可少量改动REdis源代码,实现从节点重启后的部分复制。

正常情况下,主节点会往从节点连接缓冲区写一份数据,同时往repl_backlog也写一份数据,所有从节点共享同一份repl_backlog,因此可以考虑repl_backlog配置大一点,以容忍从节点更长时间失联。

从节点向主节点发送命令PSYNC,触发部分复制。有关REdis主从复制的细节,请参见《REdis复制研究》。

2. 配置项

REdis的复制分全量复制和部分复制,全量复制是个很重的过程,而部分复制则是轻量的,部分复制实际是一个增量复制。

REdis的主节点创建和维护一个环形缓冲复制队列(即repl_backlog),从节点部分复制(增量复制)的数据均来自于repl_backlog。

主节点只有一个repl_backlog,所有从节点共享,直接相关的配置项有两个:

配置项名

配置项说明

repl-backlog-size

环形缓冲复制队列大小,可不带单位,但同时支持单位:b、k、kb、m、mb、g、gb,单位不区分大小写,其中k、m、g间的计算倍数是1000,而kb、mb和gb的计算倍数是1024。

repl-backlog-ttl

环形缓冲复制队列存活时长(所有slaves不可用时,保留repl_backlog多长时间,单位:秒)

3. redisServer

结构体redisServer是REdis的第一核心结构,repl_backlog是它的组成成员。

struct redisServer {

/* My current replication offset */

long long master_repl_offset;

/* Accept offsets up to this for replid2. */

long long second_replid_offset;

/* Replication backlog for partial syncs */

char *repl_backlog; // 环形缓冲复制队列

/* Backlog circular buffer size */

long long repl_backlog_size; // 环形缓冲复制队列容量

/* Backlog actual data length */

long long repl_backlog_histlen// 环形缓冲复制队列已用大小(影响是否能部分复制)

/* Backlog circular buffer current offset,

that is the next byte will'll write to.*/

// 实际上谈不上空闲,因为总是环绕覆盖写,

// 理解为最新数据的截止位置更为合适,更新的数据总是从这里开始写入到repl_backlog中。

long long repl_backlog_idx; // 环形缓冲复制队列空闲起始位置(从这里开始)

/* Replication "master offset" of first

byte in the replication backlog buffer.*/

long long repl_backlog_off// 数据在环形缓冲复制队列的起始位置从这里开始)

/* Time without slaves after the backlog

gets released. */

time_t repl_backlog_time_limit; // 环形缓冲复制队列生存时长

/* We have no slaves since that time.

Only valid if server.slaves len is 0. */

time_t repl_no_slaves_since; // 无可用从节点的发生时间

/* Min number of slaves to write. */

int repl_min_slaves_to_write; // 最小需写的从节点数

/* Max lag of <count> slaves to write. */

int repl_min_slaves_max_lag;

/* Number of slaves with lag <= max_lag. */

int repl_good_slaves_count;

/* Send RDB to slaves sockets directly. */

int repl_diskless_sync; // 不落磁盘(无盘)往从节点发送RDB(全量复制)

/* Delay to start a diskless repl BGSAVE. */

// 无盘复制时,延迟指定的时长,以等待更多的从节点

int repl_diskless_sync_delay;

};

4. feedReplicationBacklog-写repl_backlog

/* Add data to the replication backlog.

* This function also increments the global replication offset stored at

* server.master_repl_offset, because there is no case where we want to feed

* the backlog without incrementing the offset. */

// 主要被replicationFeedSlaves调用

// len长的数据ptr到repl_backlog中

// repl_backlog是一个环形buffer,不存在溢出的问题,策略是最新数据覆盖最老数据

// 如果参数len大于repl_backlog_size,

// 则repl_backlog没有实际意义,

// 因为无法存储一份完整数据。

void feedReplicationBacklog(void *ptr, size_t len) {

unsigned char *p = ptr;

server.master_repl_offset += len;

/* This is a circular buffer, so write as much data we can at every

* iteration and rewind the "idx" index if we reach the limit. */

// 因为repl_backlog是环形buffer,

// 剩余的空间可能容纳不了len长的数据,

// 当不够时,就需要环绕从头开始写,

// 因此这里需while循环。

while(len) {

// repl_backlog_size为repl_backlog的容量大小,

// 由配置项决定repl_backlog_size值决定,

// repl_backlog_idx是repl_backlog空闲区域的起始位置,

// 这两个值相减得到repl_backlog可用大小。

size_t thislen = server.repl_backlog_size - server.repl_backlog_idx;

// 如果thislen大于len,则表示足够容纳

if (thislen > len) thislen = len;

memcpy(server.repl_backlog+server.repl_backlog_idx,p,thislen);

// 空闲位置往后挪动

server.repl_backlog_idx += thislen;

// 如果空闲位置达到容量大小,则环绕回去从0开始

if (server.repl_backlog_idx == server.repl_backlog_size)

server.repl_backlog_idx = 0;

len -= thislen;

p += thislen;

// repl_backlog_histlen记录了repl_backlog中的数据大小

server.repl_backlog_histlen += thislen;

}

// 修正存储在repl_backlog中的数据大小,

// 它不可能超过repl_backlog_size值。

if (server.repl_backlog_histlen > server.repl_backlog_size)

server.repl_backlog_histlen = server.repl_backlog_size;

/* Set the offset of the first byte we have in the backlog. */

server.repl_backlog_off = server.master_repl_offset -

server.repl_backlog_histlen + 1;

}

5. addReplyReplicationBacklog-读repl_backlog

当主节点判断可部分复制时,会记录如下日志:

Partial resynchronization request from %s accepted. Sending %lld bytes of backlog starting from offset %lld.

给从节点的响应头为“+CONTINUE replid\r\n”或“+CONTINUE\r\n”。函数addReplyReplicationBacklog的实现:

/* Feed the slave 'c' with the replication backlog starting from the

* specified 'offset' up to the end of the backlog. */

// 被masterTryPartialResynchronization调用

// 而masterTryPartialResynchronizationsyncCommand调用(对应命令PSYNC)。

// 从repl_backlog取数据发给slave,

// 数据的开始位置由offset指定。

long long addReplyReplicationBacklog(client *c, long long offset) {

long long j, skip, len;

serverLog(LL_DEBUG, "[PSYNC] Replica request offset: %lld", offset);

// repl_backlog_histlen为0,

// 表示repl_backlog中无数据。

if (server.repl_backlog_histlen == 0) {

serverLog(LL_DEBUG, "[PSYNC] Backlog history len is zero");

return 0;

}

serverLog(LL_DEBUG, "[PSYNC] Backlog size: %lld",

server.repl_backlog_size);

serverLog(LL_DEBUG, "[PSYNC] First byte: %lld",

server.repl_backlog_off);

serverLog(LL_DEBUG, "[PSYNC] History len: %lld",

server.repl_backlog_histlen);

serverLog(LL_DEBUG, "[PSYNC] Current index: %lld",

server.repl_backlog_idx);

/* Compute the amount of bytes we need to discard. */

skip = offset - server.repl_backlog_off;

serverLog(LL_DEBUG, "[PSYNC] Skipping: %lld", skip);

/* Point j to the oldest byte, that is actually our

* server.repl_backlog_off byte. */

j = (server.repl_backlog_idx +

(server.repl_backlog_size-server.repl_backlog_histlen)) %

server.repl_backlog_size;

serverLog(LL_DEBUG, "[PSYNC] Index of first byte: %lld", j);

/* Discard the amount of data to seek to the specified 'offset'. */

j = (j + skip) % server.repl_backlog_size;

/* Feed slave with data. Since it is a circular buffer we have to

* split the reply in two parts if we are cross-boundary. */

len = server.repl_backlog_histlen - skip;

serverLog(LL_DEBUG, "[PSYNC] Reply total length: %lld", len);

while(len) {

long long thislen =

((server.repl_backlog_size - j) < len) ?

(server.repl_backlog_size - j) : len;

serverLog(LL_DEBUG, "[PSYNC] addReply() length: %lld", thislen);

addReplySds(c,sdsnewlen(server.repl_backlog + j, thislen));

len -= thislen;

j = 0;

}

return server.repl_backlog_histlen - skip;

}

REdis主从复制之repl_backlog相关推荐

  1. [转载] 深入剖析 redis 主从复制

    转载自http://www.cnblogs.com/daoluanxiaozi/p/3724299.html 主从概述 redis 支持 master-slave(主从)模式,redis server ...

  2. Redis主从复制配置

    环境描述 Redis Master:192.168.1.100 6379(Ubuntu系统) Redis Slave1:192.168.1.101 6380(Ubuntu系统) Redis Slave ...

  3. redis主从复制故障转移

    Redis主从复制与故障切换 目录 目录1 一.概述1 二. 实验目的2 三.试验环境2 四. 说明2 五. 拓扑2 六. 实施步骤2 6.1.分别安装redis2.8.32 6.2.配置主从同步3 ...

  4. redis+主从复制+集群配置

    redis+主从复制+集群配置 redis是一个key-value存储系统.和memcached类似,不过redis支持的value类型更多,主要有:string(字符串).list(链表).set( ...

  5. cxgrid主从表 点+号展开_深入理解Redis主从复制

    一.背景 前面的文章中,我们介绍过Redis的持久化机制,它可以实现Redis实例数据的crash-safe.但是这里有一个问题,就是Redis其实还存在着单点故障问题,比如说Redis的硬盘坏掉了, ...

  6. Redis主从复制下的工作原理

    Redis主从复制下的工作原理 Redis主从复制的配置十分简单,它可以使从服务器是主服务器的完全拷贝.需要清楚Redis主从复制的几点重要内容: 1)Redis使用异步复制.但从Redis 2.8开 ...

  7. php连接redis 主从复制,redis怎么进行主从复制

    redis主从复制同步实现的过程 1.从服务发送一个sync同步命令给主服务要求全量同步 (推荐学习:Redis视频教程) 2.主服务接收到从服务的sync同步命令时,会fork一个子进程后台执行bg ...

  8. redis主从复制如何保证数据一致性_面试官:Redis 主从复制时网络开小差了怎么整?...

    上周因为实在太忙就认认真真写了一篇水文,吹了一下自己过去的经历,反响竟然超出了我的预期,并且后台还有读者留言表示想看续集的.哈哈,果然大家还是对水文更有热情. 这期我们继续回到之前的 Redis 话题 ...

  9. Redis主从复制的搭建与.哨兵.数据持久

    目录 一.redis主从复制 1.主从复制的概述 2.一主一从结构的配置 二.哨兵服务 1. 哨兵服务的简单介绍 2.配置哨兵服务 三.数据持久化 1.RedisDataBase(RDB) 2.App ...

最新文章

  1. python使用matplotlib可视化、自定义移除X轴指定轴刻度标签(removing specific axis ticks in matplotlib x axis)
  2. 网站后台的lnmp启动与重启
  3. Redis(1)---五种数据结构
  4. 春节假期前5天全国快递处理量达3.65亿件 同比增长224%
  5. win10计算机无法远程连接,win10无法远程连接
  6. 搭建fabric-sample/balance-transfer网络详解
  7. keep怎么生成运动轨迹_空间新物种 !| 垂直运动路径与商业综合体的整合与植入...
  8. 竞价实例-让ESS省上加省
  9. Xshell5(远程终端工具)工具的安装使用 【免费】
  10. 读书,读一本好书,让我们得以明净如水
  11. ubuntu18.04 netplan 设置dns,dns不生效
  12. OSError: [WinError 193] %1 不是有效的 Win32 应用程序。
  13. 购买一台计算机需要哪些配件,组装一台电脑需要哪些配件【详细列举】
  14. arm嵌入式led灯闪烁实验报告_嵌入式ARM键盘控制LED灯实验报告
  15. ISP算法----AWB总结及源代码
  16. Mr.Go 会客厅第二期,B站+斗鱼“后浪” Gopher 火花四溅!
  17. 微信头像挂件来了,想在头像加什么就来加什么吧!
  18. opencv c++ Harris角点检测、shi-tomasi角点
  19. 卷积神经网络 神经网络,卷积神经网络基础知识
  20. 根据Spring-Security安全框架搭建问答论坛系统(更新中.....)

热门文章

  1. c++thread里暂停线程_C语言如何正确的终止正在运行的子线程
  2. python右对齐输出乘法表_python打印输出九九乘法表
  3. ubuntu下vscode配置C++项目编译调试(json文件),以高翔octomap教程为例,顺便解决vscode无法设置断点问题.
  4. Python3实现Two-Pass算法检测区域连通性
  5. 极速版迅雷 服务器响应超时,迅雷登录超时怎么回事_迅雷经常登录超时如何解决...
  6. 梦中香巴拉——云南游记
  7. 在c语言中开辟一个数组空间,c语言如何在动态的结构体数组开辟新空间
  8. 新网站关键词优化小技巧
  9. 如何读博士-2021.06.12
  10. keras读取h5文件load_weights、load代码操作