You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@rocketmq.apache.org by goman <28...@qq.com> on 2017/06/11 09:21:12 UTC

关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题

hi all,想请教个问题


我在4.0.0源码看到多slave同步复制时,只要一个slave复制成功broker就会回复producer ResponseCode.SUCCESS。细节如下:


CommitLog在进行同步双写时,会提交一个GroupCommitRequest到HaService的请求队列,
之后会调用 request.waitForFlush(long timeout) 方法阻塞等待复制结果。


在HaService里会执行以下方法来唤醒阻塞的request
private void doWaitTransfer() {
    synchronized (this.requestsRead) {
        if (!this.requestsRead.isEmpty()) {
            for (CommitLog.GroupCommitRequest req : this.requestsRead) {
                boolean transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                for (int i = 0; !transferOK && i < 5; i++) {
                    this.notifyTransferObject.waitForRunning(1000);
                    transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                }


                if (!transferOK) {
                    log.warn("transfer messsage to slave timeout, " + req.getNextOffset());
                }


                req.wakeupCustomer(transferOK);
            }


            this.requestsRead.clear();
        }
    }
}


通过红色代码可以看出只要HaService.push2SlaveMaxOffset达到了request的nextOffset就认为同步成功。


而HaService.push2SlaveMaxOffset的变更,是由HAConnection.ReadSocketService在收到slave复制成功并发送的readOffset后,调用HaService.notifyTransferSome(final long offset)进行变更的。
问题就在这里,一个HaService会持有n个HaConnection(对应n个slave),所以只要一个slave发送了readOffset就会最终触发request.wakeupCustomer(transferOK);


如果我以上的理解没错,回到邮件的标题,假设现在是1主2从,当msg被A从复制成功但B从复制失败时master宕机了,一段时间后consumer会切换到slave进行消费,但此时有可能切换到消费B从(切换到 brokerAddrMap 的第一个entry),也就会出现虽然A从有msg但不会被消费到的“假丢失”现象。


如果我的理解没错,那么在主备切换机制还不具备的条件下能否先使用一个简单方案,在消费broker时加一个判断,没有master broker时进行一次所有slave的访问获取他们的offset;如果存在offset不一致的情况,则在master出现前只消费这个offset最大的slave,以此来解决“假丢失”问题?

回复:关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题

Posted by goman <28...@qq.com>.
各位对我提的问题有什么看法?


还是说我理解错了?





------------------ 原始邮件 ------------------
发件人: "goman";<28...@qq.com>;
发送时间: 2017年6月11日(星期天) 下午5:25
收件人: "users"<us...@rocketmq.incubator.apache.org>; 

主题: 回复:关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题



不好意思,补充一下,前文说的“红色代码”指的是这行


transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();





------------------ 原始邮件 ------------------
发件人: "goman";<28...@qq.com>;
发送时间: 2017年6月11日(星期天) 下午5:21
收件人: "users"<us...@rocketmq.incubator.apache.org>; 

主题: 关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题



hi all,想请教个问题


我在4.0.0源码看到多slave同步复制时,只要一个slave复制成功broker就会回复producer ResponseCode.SUCCESS。细节如下:


CommitLog在进行同步双写时,会提交一个GroupCommitRequest到HaService的请求队列,
之后会调用 request.waitForFlush(long timeout) 方法阻塞等待复制结果。


在HaService里会执行以下方法来唤醒阻塞的request
private void doWaitTransfer() {
    synchronized (this.requestsRead) {
        if (!this.requestsRead.isEmpty()) {
            for (CommitLog.GroupCommitRequest req : this.requestsRead) {
                boolean transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                for (int i = 0; !transferOK && i < 5; i++) {
                    this.notifyTransferObject.waitForRunning(1000);
                    transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                }


                if (!transferOK) {
                    log.warn("transfer messsage to slave timeout, " + req.getNextOffset());
                }


                req.wakeupCustomer(transferOK);
            }


            this.requestsRead.clear();
        }
    }
}


通过红色代码可以看出只要HaService.push2SlaveMaxOffset达到了request的nextOffset就认为同步成功。


而HaService.push2SlaveMaxOffset的变更,是由HAConnection.ReadSocketService在收到slave复制成功并发送的readOffset后,调用HaService.notifyTransferSome(final long offset)进行变更的。
问题就在这里,一个HaService会持有n个HaConnection(对应n个slave),所以只要一个slave发送了readOffset就会最终触发request.wakeupCustomer(transferOK);


如果我以上的理解没错,回到邮件的标题,假设现在是1主2从,当msg被A从复制成功但B从复制失败时master宕机了,一段时间后consumer会切换到slave进行消费,但此时有可能切换到消费B从(切换到 brokerAddrMap 的第一个entry),也就会出现虽然A从有msg但不会被消费到的“假丢失”现象。


如果我的理解没错,那么在主备切换机制还不具备的条件下能否先使用一个简单方案,在消费broker时加一个判断,没有master broker时进行一次所有slave的访问获取他们的offset;如果存在offset不一致的情况,则在master出现前只消费这个offset最大的slave,以此来解决“假丢失”问题?

回复:关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题

Posted by goman <28...@qq.com>.
不好意思,补充一下,前文说的“红色代码”指的是这行


transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();





------------------ 原始邮件 ------------------
发件人: "goman";<28...@qq.com>;
发送时间: 2017年6月11日(星期天) 下午5:21
收件人: "users"<us...@rocketmq.incubator.apache.org>; 

主题: 关于在多 slave 同步复制模式下, master 宕机导致的消息“假丢失”问题



hi all,想请教个问题


我在4.0.0源码看到多slave同步复制时,只要一个slave复制成功broker就会回复producer ResponseCode.SUCCESS。细节如下:


CommitLog在进行同步双写时,会提交一个GroupCommitRequest到HaService的请求队列,
之后会调用 request.waitForFlush(long timeout) 方法阻塞等待复制结果。


在HaService里会执行以下方法来唤醒阻塞的request
private void doWaitTransfer() {
    synchronized (this.requestsRead) {
        if (!this.requestsRead.isEmpty()) {
            for (CommitLog.GroupCommitRequest req : this.requestsRead) {
                boolean transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                for (int i = 0; !transferOK && i < 5; i++) {
                    this.notifyTransferObject.waitForRunning(1000);
                    transferOK = HAService.this.push2SlaveMaxOffset.get() >= req.getNextOffset();
                }


                if (!transferOK) {
                    log.warn("transfer messsage to slave timeout, " + req.getNextOffset());
                }


                req.wakeupCustomer(transferOK);
            }


            this.requestsRead.clear();
        }
    }
}


通过红色代码可以看出只要HaService.push2SlaveMaxOffset达到了request的nextOffset就认为同步成功。


而HaService.push2SlaveMaxOffset的变更,是由HAConnection.ReadSocketService在收到slave复制成功并发送的readOffset后,调用HaService.notifyTransferSome(final long offset)进行变更的。
问题就在这里,一个HaService会持有n个HaConnection(对应n个slave),所以只要一个slave发送了readOffset就会最终触发request.wakeupCustomer(transferOK);


如果我以上的理解没错,回到邮件的标题,假设现在是1主2从,当msg被A从复制成功但B从复制失败时master宕机了,一段时间后consumer会切换到slave进行消费,但此时有可能切换到消费B从(切换到 brokerAddrMap 的第一个entry),也就会出现虽然A从有msg但不会被消费到的“假丢失”现象。


如果我的理解没错,那么在主备切换机制还不具备的条件下能否先使用一个简单方案,在消费broker时加一个判断,没有master broker时进行一次所有slave的访问获取他们的offset;如果存在offset不一致的情况,则在master出现前只消费这个offset最大的slave,以此来解决“假丢失”问题?