REdis主从复制之repl_backlog

REdis主从复制之repl_backlog

目录

目录 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

环形缓冲复制队列大小,可不带单位,但同时支持单位:bkkbmmbggb,单位不区分大小写,其中kmg间的计算倍数是1000,而kbmbgb的计算倍数是1024

repl-backlog-ttl

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

3. redisServer

结构体redisServerREdis的第一核心结构,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调用

// 而masterTryPartialResynchronization被syncCommand调用(对应命令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;

}

 

 

 

转载于:https://www.cnblogs.com/aquester/p/10978366.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100880.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 为什么投屏找不到设备(投屏电视显示无法访问服务器)

    现在液晶电视价格越来越便宜,很少的钱就可以买一台60寸以上的电视,那么使用电脑的朋友一定想要把画面投屏到电视上,用于玩游戏、看电影吧!Win10就有非常好用的投屏功能,很多朋友可能不知道如何操作,这里小编和大家分享下具体步骤:Win10投屏电视步骤如下:(以小米电视为例)1、首先将电脑连接无线WIFI。2、将电视也连接在同一个无线WIFI网络下。3、进入电视应用中,选择“无线显示”功能。(不同的型…

  • nuget的原理_NuGet 跨平台插件

    nuget的原理_NuGet 跨平台插件NuGet跨平台插件NuGetcrossplatformplugins07/01/2018本文内容已添加NuGet4.8+跨平台插件支持。InNuGet4.8+supportforcrossplatformpluginshasbeenadded.这是通过生成新的插件扩展性模型实现的,该模型必须符合一组严格的操作规则。Thiswasachievedwith…

    2022年10月31日
  • ASMM与AMM「建议收藏」

    ASMM与AMM「建议收藏」ASMM(AutomaticSharedMemoryManagement,自动共享内存管理)是Oracle10g引入的概念。通过使用ASMM,就不需要手工设置相关内存组件的大小,而只为SGA设置一个总的大小,Oracle的MMAN进程(MemoryManagerProcess,内存管理进程)会随着时间推移,根据系统负载的变化和内存需要,自动调整SGA中各个组件的内存大小。ASMM的…

  • ubuntu14.04源代码安装postgresql 9.1

    ubuntu14.04源代码安装postgresql 9.1

  • 20130828可注册域名列表

    20130828可注册域名列表aabkx.comaapun.comabmrw.comabnks.comacphq.comacsgq.comactcL.comaderz.comadjni.comadojj.comadyjy.comafabd.comafcfx.comafrhi.comafubd.comahscp.comaihtt.comaimfp.comai

  • dpkg安装软件流程_DPKG命令与软件安装、APT[通俗易懂]

    dpkg安装软件流程_DPKG命令与软件安装、APT[通俗易懂]====Linux软件包====Linux系统中,软件通常以源代码或者预编译包的形式提供。软件的源代码通常需要编译为二进制代码才可使用,安装比较耗时。用户可以自行调节编译选项,决定需要的功能或组件,或者针对硬件平台作一些优化预编译包通常由软件发布者进行编译,用户只要将预编译包拷贝到系统中即可。考虑到预编译包的通用性,预编译包一般不会针对某种硬件平台优化,所包含的功能和组件也是通用的组合。ubunt…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号