Redis 4.0 PSYNC2中second_replid_offset探究

Redis 4.0起引入了PSYNC2同步方式,分析源码时我们注意到,server数据中增加了replid2second_replid_offset两个成员。进一步分析逻辑可知,这两个成员是在master变更后,在slave中用于保存原master的ID和已同步的数据偏移的。那他们有什么作用呢?

PSYNC2用以提高特定情况下的从机数据同步效率。比如对于以下拓补

   A
   +
   |
 +---+
 |   |
 v   v
 B   C

A为master,A同步数据到B、C。当A故障后,假如B被选为新的master,C成为B的从机。在过去C需要做一次数据全同步才能重新提供服务;而支持PSYNC2后,C大概率只需要从B同步最新的自己还没有接收到的数据即可,就好像自己的master还是A,只是短暂掉线重连了一样。PSYNC2相关的详细资料网络上已有很多,本文不再赘述。

上面提到,C大概率只需要从B同步最新的自己还没有接收到的数据,那就意味着有些情况下C还是需要全同步B的的。考虑下面的情况,还是A同步数据到B、C,当A中最新数据偏移为250时A故障下线,此时B接收到的最新数据偏移为200、C为175。

   +----------------+          +----------------+          +----------------+
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |   last_byte    |          |                |          |                |
   +----------------+250       |                |          |                |
   |                |          |                |          |                |
   |                +--------> +----------------+200       |                |
   |                |          |                |          +----------------+175
   |                |          |    received    |          |                |
   |                |          |     from A     |          |    received    |
   |                |          |                |          |     from A     |
   |                |          |                |          |                |
   +----------------+          +----------------+          +----------------+
        Redis A                     Redis B                     Redis C

经过哨兵调度,B成为新的master,C成为B的从机。经过一段短暂的时间,B最新数据偏移到达300,而C从B处也接收到了所有数据。此时A恢复了,上线后被哨兵调度为B的从机。因为A之前的最新数据偏移为250,所以发送PSYNC指令请求从251开始部分同步数据。如果B不做判断从251位置开始给A发送数据,很显然A中201-250这一段数据将与B、C中 的不一致。因为A故障后,201-250的数据尚未来得及同步给B,而B在后来已经将新数据追加到从A同步来的的200字节之后了,这些数据与A中的数据是不一致的。

   +----------------+          +----------------+          +----------------+
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |                |          |                |
   |                |          |   last byte    |          |                |
   +----------------+          +----------------+300       +----------------+300
   |  recv from B   |          |                |          |                |
   +----------------+250<---X--+    new data    |          |    received    |
   |  inconsistent  |          |                |          |     from B     |
   +----------------+          +----------------+200       |                |
   |                |          |                |          +----------------+175
   |   consistent   |          |    received    |          |                |
   |                |          |     from A     |          |    received    |
   |                |          |                |          |     from A     |
   |                |          |                |          |                |
   +----------------+          +----------------+          +----------------+
        Redis A                     Redis B                     Redis C

为了避免上述问题,B需要记住原master的ID,以及从原master获得的数据偏移。当有从机带着原master的ID来请求数据时,需要先检查请求的偏移量是否超过了自己已获得的数据量。如果是,那么从机需要丢弃所有数据并做全同步,以确保数据一致。这就是replid2second_replid_offset的作用。详见replication.c:masterTryPartialResynchronization()中这段逻辑:

    /* Is the replication ID of this master the same advertised by the wannabe
     * slave via PSYNC? If the replication ID changed this master has a
     * different replication history, and there is no way to continue.
     *
     * Note that there are two potentially valid replication IDs: the ID1
     * and the ID2. The ID2 however is only valid up to a specific offset. */
    if (strcasecmp(master_replid, server.replid) && //当前server的ID不是master的ID
        (strcasecmp(master_replid, server.replid2) || //并且,自己上一个master不是从机的master 或 
         psync_offset > server.second_replid_offset)) //是同一个master但从机要求的偏移比自己接收的数据还大
    {
        /* Run id "?" is used by slaves that want to force a full resync. */
        if (master_replid[0] != '?') {
            if (strcasecmp(master_replid, server.replid) &&
                strcasecmp(master_replid, server.replid2))
            {
                serverLog(LL_NOTICE,"Partial resynchronization not accepted: "
                    "Replication ID mismatch (Slave asked for '%s', my "
                    "replication IDs are '%s' and '%s')",
                    master_replid, server.replid, server.replid2);
            } else {
                serverLog(LL_NOTICE,"Partial resynchronization not accepted: "
                    "Requested offset for second ID was %lld, but I can reply "
                    "up to %lld", psync_offset, server.second_replid_offset);
            }
        } else {
            serverLog(LL_NOTICE,"Full resync requested by slave %s",
                replicationGetSlaveName(c));
        }
        goto need_full_resync;
    }

那么,A中原来的201-250的那段数据呢?丢了呗,还能咋滴。。。要不怎么说Redis并不可靠,不要当关键存储用。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码农阿宇

windows下安装MongoDB进度条不动

windows 下安装MongoDB, 在  Installing MongoDB Compass...(this may take a few minutes...

42940
来自专栏Spark学习技巧

Kafka源码系列之使用要点总结及重要错误解决

1,创建一个topic bin/kafka-topics.sh --create --zookeeper localhost:2181 --replicatio...

23960
来自专栏向治洪

hibernate 5.2.6新特性

概述 Hibernate ORM 5.2.6 发布了,Hibernate是一种Java语言下的对象关系映射解决方案。 它是使用GNU宽通用公共许可证发行的自由、...

22690
来自专栏陈树义

你绝不能错过的效率神器 —— Alfred

? Alfred 是 Mac 系统上一款专注于效率提升的著名应用,它能帮你快速打开网页、快速进行自定义搜索、查看剪贴板历史、快速查询单词等等。Alfred 提...

1.2K70
来自专栏数据和云

颜值实力派—打造MySQL运行监控环境

作者 | 陈龙,云和恩墨西区工程师,一线服务过金融等行业,精通 oracle 性能优化,故障诊断,特殊恢复领域 。

14020
来自专栏Java职业技术分享

Java异步NIO框架Netty实现高性能高并发

最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调...

92610
来自专栏LanceToBigData

JavaWeb之MVC模式

一、什么是MVC设计模式? MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Mode...

32880
来自专栏张善友的专栏

REST In WCF4.0

REST软件架构是由Roy Thomas Fielding博士2000年在他的论文《Architectural Styles and the Design o...

203100
来自专栏FreeBuf

现代版荆轲刺秦王:Struts2 REST插件漏洞分析

战国末期,大秦实力强盛,大有横扫六合之势,在灭了韩、赵两国后,下一个目标就是燕国。

11520
来自专栏吴伟祥

9个基于Java的搜索引擎框架 转

在这个信息相当繁杂的互联网时代,我们已经学会了如何利用搜索引擎这个强大的利器来找寻目标信息,比如你会在Google上搜索情人节如何讨女朋友欢心,你也会在百度上寻...

47140

扫码关注云+社区

领取腾讯云代金券