RocketMQ是如何判断flushOK,及4.2版本所出现的疑问

RocketMQ

版本:rocketmq-4.2.0

bug所表现形式:在同步刷盘时,生产消息,返回SendResult的SendStatus为FLUSH_DISK_TIMEOUT,而且是在发送消息总量大概mapedFileSizeCommitLog(默认配置1G)的时候出现,每次达到mapedFileSizeCommitLog大小左右的时候都会出现FLUSH_DISK_TIMEOUT。而其余时间并没有出现状态,总是如此这显然是有问题的。

rocketmq刷盘逻辑:引用:https://blog.csdn.net/prestigeding/article/details/79188383

RocketMQ是如何判断flushOK?

刷盘:CommitLog.this.mappedFileQueue.flush(0)

原理:根据刷盘起始点【CommitLog.this.mappedFileQueue.getFlushedWhere()】和下次刷盘点【req.getNextOffset()】的比较来判断是否成功刷入磁盘。由于一条消息可能在下一个分片存储,故循环次数为2。

代码:

private void doCommit() {

            synchronized (this.requestsRead) {

                if (!this.requestsRead.isEmpty()) {

                    for (GroupCommitRequest req : this.requestsRead) {

                        // There may be a message in the next file, so a maximum of

                        // two times the flush

                        boolean flushOK = false;

                        for (int i = 0; i < 2 && !flushOK; i++) {

                            flushOK = CommitLog.this.mappedFileQueue.getFlushedWhere() >= req.getNextOffset();

                            if (!flushOK) {

                                CommitLog.this.mappedFileQueue.flush(0);

                            }

                        }

                        req.wakeupCustomer(flushOK);

                    }

                    long storeTimestamp = CommitLog.this.mappedFileQueue.getStoreTimestamp();

                    if (storeTimestamp > 0) {

                        CommitLog.this.defaultMessageStore.getStoreCheckpoint().setPhysicMsgTimestamp(storeTimestamp);

                    }

                    this.requestsRead.clear();

                } else {

                    // Because of individual messages is set to not sync flush, it

                    // will come to this process

                    CommitLog.this.mappedFileQueue.flush(0);

                }

            }

        }

 

先讲正常流程:进入for循环,第一次:由于刷盘起始点【CommitLog.this.mappedFileQueue.getFlushedWhere()】小于下次刷盘点【req.getNextOffset()】,故flushOK为false,执行刷盘操作。第二次:由于刷盘成功,刷盘起始点【CommitLog.this.mappedFileQueue.getFlushedWhere()】等于下次刷盘点【req.getNextOffset()】,flushOK为true。结束循环。

bug出现了:若有一个消息在下个MappedFile来存储,第一次flushOK为false,刷盘之后刷盘起始点【CommitLog.this.mappedFileQueue.getFlushedWhere()】还是小于下次刷盘点【req.getNextOffset()】,故开始第二次刷盘。而第二次刷盘成功,而这时循环却结束了。可flushOK还是为false。

修改代码:在for循环外再加flushOK的判断。

RocketMQ是如何判断flushOK,及4.2版本所出现的疑问_第1张图片

 

 

 

 

 

 

你可能感兴趣的:(RocketMQ)