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的判斷。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章