V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mightofcode
V2EX  ›  Redis

redis 主从同步会有命令丢失?

  •  
  •   mightofcode · 2020-04-01 22:02:30 +08:00 · 5842 次点击
    这是一个创建于 1700 天前的主题,其中的信息可能已经有所发展或是发生改变。

    《 redis 》设计与实现 218 页,15.7.3”检测命令丢失“

    ”但这条命令却因为网络故障而在传播的过程中丢失,那么主从服务器之间的复制偏移量就会出现不一致“

    主从之间是 tcp 连接,已经保证了可靠传输,为什么还要考虑”命令丢失“?

    10 条回复    2022-04-08 13:06:45 +08:00
    yyfearth
        1
    yyfearth  
       2020-04-02 07:17:59 +08:00
    可是 TCP 可靠传输 没办法解决掉线的问题啊 就算重传也是有时间或者次数限制的
    ppyybb
        2
    ppyybb  
       2020-04-02 11:32:41 +08:00
    这个地方我当时看的时候也有疑惑,一个可能的猜测:
    如果因为超过重传限制,关闭了 tcp 流,那么 master 不知道 slave 到底接受到多少了。这个时候重新 connect 一个链接又成功了,那么也需要从应用层面来判断丢了哪些偏移量。
    mingtiny11
        3
    mingtiny11  
       2020-04-02 14:40:41 +08:00
    你先理解一下 tcp 的可靠传输什么意思
    RedisMasterNode
        4
    RedisMasterNode  
       2020-04-02 16:02:31 +08:00
    是否 TCP 连接建立之后,所有的传输都必定抵达,必定能够组合回原来的内容?
    mightofcode
        5
    mightofcode  
    OP
       2020-04-02 21:08:14 +08:00
    @yyfearth 这个解释靠谱
    mightofcode
        6
    mightofcode  
    OP
       2020-04-02 21:09:56 +08:00
    @ppyybb 是否可以理解为应用层的可靠性保障,避免断网等异常情况造成不一致
    yyfearth
        7
    yyfearth  
       2020-04-03 06:44:26 +08:00
    @RedisMasterNode 任何事情没有绝对 而且有可能抵达不了啊
    @mightofcode TCP 只管连接传输层面的可靠性 没办法保证应用层数据的可靠性
    所以 TCP 接传输层可靠性保证不能保证命令不丢失
    TCP 没有聪明到断开重联后会帮你把应用层丢失的数据重传 这个是应用层的事情
    所以“检测命令丢失”是应用层的逻辑和是不是 TCP 没有关系

    打个比方 快递公司可以保证包裹从仓库一定能够送到你家门口
    但是不能保证你一定能够收到你的包裹
    比如仓库丢了或弄错了包裹 仓库关门了 再比如你家门口包裹被别人拿走了
    更不能保证包裹里面的东西一定是你想要的
    因为这个和快递公司没有半毛线关系

    现在用 UDP 做 一样可以做到可靠传输 只不过是应用层来实现的
    比如 HTTP3/QUIC 就已经从 TCP 换到 UDP 了
    ppyybb
        8
    ppyybb  
       2020-04-03 11:22:05 +08:00
    @mightofcode 是的,我是这样理解的。考虑这样的情况,ping 的命令本身也是在 tcp 去传输的,如果网络通不了,那么它自己也不可能比前面的命令先到达(假设 ping 没有单独开链接), 所以认为是链接断了重连这种情况是比较合理的。再说这种应用层的保证也算是一种兜底逻辑,万一以后改动导致复制有偶然的 bug 了,至少有这个信息流通还能抢救一下,不至于太大影响...
    Jaron0608
        9
    Jaron0608  
       2021-03-20 11:58:37 +08:00
    同对这里有疑问
    但是疑惑的是:
    master 发现 slave 上报的 offset 落后就触发重传命令,会不会导致命令的重复执行呢,因为完全存在 slave 发送 replconf ack <offset>的时候,网络中还有 master 发过来的命令没有到达啊。
    cocong
        10
    cocong  
       2022-04-08 13:06:45 +08:00
    @Jaron0608

    没错,而且还有其它很多问题。master 发送给 slave 命令后,并不会等 slave 收到并确认后才更新自己的偏移量,而心跳检测 replconf ack <offset> 默认是每秒执行一次。所以有可能 master 发送给 slave 命令后,偏移量为 100 ,但这个请求还未到达 slave ,此时 slave 执行心跳检测 replconf ack 90 ,master 就会发现 slave 的偏移量和自己不一致,于是 master 就会再次发送重复的命令。

    作者把管这叫命令丢失,我觉得是完全错误的。TCP 本来就是可靠传输,正常连接是不可能出现命令丢失,而且绝对是有序的。第一个回答说 TCP 重传是有时间或者次数限制的,可是超过限制,TCP 连接就会自动断开,也就是掉线问题。既然掉线了,那 slave 不是要和 master 重连吗?重连后不是重新 psync 吗? psync 本身不就是为了解决这种问题吗?

    所以 命令丢失 -> TCP 断开 -> slave 重连 -> psync ,所以我觉得书中说的 主服务器收到 replconf ack <offset> ,发现偏移量比自己小就重发,这完全是多余的,和 命令丢失 完全没有关系。

    再仔细思考,心跳检测最重要的作用就是检测主从服务器的网络状态。如果网络正常,那么之前主服务器发送给从服务器的命令肯定没问题,如果网络有问题,就重连,psync 能够解决一致性问题。这样看来,心跳检测加个 offset 完全没有必要,画蛇添足的感觉。当然,这种结论仅限于 TCP 层,如果是从服务器自己出了问题,那这个心跳检测加的 offset 就能发挥兜底的作用,但书中说的是因为网络故障导致的命令丢失。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3579 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:52 · PVG 18:52 · LAX 02:52 · JFK 05:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.