RocketMQ文件過期策略詳解

原文鏈接:https://www.jianshu.com/p/96a011a30d6a

1.爲什麼會有文件過期刪除機制

由於RocketMQ操作CommitLog、ConsumeQueue文件是基於文件內存映射機制,並且在啓動的時候會將所有的文件加載,爲了避免內存與磁盤的浪費、能夠讓磁盤能夠循環利用、避免因爲磁盤不足導致消息無法寫入等引入了文件過期刪除機制

2.RocketMQ刪除過期文件的思路

RocketMQ順序寫CommitLog文件、ComsumeQueue文件,所有的寫操作都會落到最後一個文件上,因此在當前寫文件之前的文件將不會有數據插入,也就不會有任何變動,因此可通過時間來做判斷,比如超過72小時未更新的文件將會被刪除

PS:RocketMQ刪除過期文件時不會關注該文件的內容是否全部被消費

3.文件過期刪除機制實現

3.1 觸發刪除的操作

image.png

由上圖可知,觸發文件清除操作的是一個定時任務,而且只有定時任務

// Resource reclaim interval
    private int cleanResourceInterval = 10000;

文件過期刪除定時任務的週期由該刪除決定,默認每10s執行一次

3.2 刪除源碼分析

MesssageSDefaultStore#CleanCommitLogService#deleteExpiredFiles

private void deleteExpiredFiles() {
//省略
}

我們一點一點來分析其中的代碼

long fileReservedTime = DefaultMessageStore.this.getMessageStoreConfig().getFileReservedTime();
int deletePhysicFilesInterval = DefaultMessageStore.this.getMessageStoreConfig().getDeleteCommitLogFilesInterval();
int destroyMapedFileIntervalForcibly = DefaultMessageStore.this.getMessageStoreConfig().getDestroyMapedFileIntervalForcibly();

上面三個屬性需要重點講解下

  1. fileReservedTime:文件過期時間,也就是從文件最後一次的更新時間到現在爲止,如果超過該時間,則是過期文件可被刪除
  2. deletePhysicFilesInterval:刪除物理文件的時間間隔,在一次定時任務觸發時,可能會有多個物理文件超過過期時間可被刪除,因此刪除一個文件後需要間隔deletePhysicFilesInterval這個時間再刪除另外一個文件,我猜測可能是由於刪除文件是一個非常耗費IO的操作,會引起消息插入消費的延遲(相比於正常情況下),所以不建議直接刪除所有過期文件
  3. destroyMapedFileIntervalForcibly:在刪除文件時,如果該文件還被線程引用,此時會阻止此次刪除操作,同時將該文件標記不可用並且紀錄當前時間戳destroyMapedFileIntervalForcibly這個表示文件在第一次刪除拒絕後,文件保存的最大時間,在此時間內一直會被拒絕刪除,當超過這個時間時,會將引用每次減少1000,直到引用 小於等於 0爲止,即可刪除該文件,實現代碼如下:

ReferenceResource#shutdown

public void shutdown(final long intervalForcibly) {
        if (this.available) {
            this.available = false;
            this.firstShutdownTimestamp = System.currentTimeMillis();
            this.release();
        } else if (this.getRefCount() > 0) {
            if ((System.currentTimeMillis() - this.firstShutdownTimestamp) >= intervalForcibly) {
                this.refCount.set(-1000 - this.getRefCount());
                this.release();
            }
        }
    }

MesssageSDefaultStore#CleanCommitLogService#deleteExpiredFiles

boolean timeup = this.isTimeToDelete();
boolean spacefull = this.isSpaceToDelete();
boolean manualDelete = this.manualDeleteFileSeveralTimes > 0;

if (timeup || spacefull || manualDelete) {
    //執行刪除邏輯
}
  1.  

     

    timeup:是否到了指定的時間點,RocketMQ可通過deleteWhere設置每天固定的時間刪除過期文件,默認是凌晨4點,由於這個參數設定是小時,因此在這1個小時內每次定時任務都能進來刪除過期的文件

    image.png

UtilAll#isItTimeToDo

public static boolean isItTimeToDo(final String when) {
        String[] whiles = when.split(";");
        if (whiles.length > 0) {
            Calendar now = Calendar.getInstance();
            for (String w : whiles) {
                int nowHour = Integer.parseInt(w);
                if (nowHour == now.get(Calendar.HOUR_OF_DAY)) {
                    return true;
                }
            }
        }

        return false;
    }
  1. spacefull:磁盤空間是否充足,磁盤不足返回true,執行過期文件刪除策略,我們進去看看this.isSpaceToDelete()這個方法

    MesssageSDefaultStore#CleanCommitLogService#isSpaceToDelete

    double ratio = DefaultMessageStore.this.getMessageStoreConfig().getDiskMaxUsedSpaceRatio() / 100.0;
    //是否立即清除
    cleanImmediately = false;
    {
        String storePathPhysic = DefaultMessageStore.this.getMessageStoreConfig().getStorePathCommitLog();
        double physicRatio = UtilAll.getDiskPartitionSpaceUsedPercent(storePathPhysic);
        if (physicRatio > diskSpaceWarningLevelRatio) { /**#1*/
            boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskFull();
            if (diskok) {
                DefaultMessageStore.log.error("physic disk maybe full soon " + physicRatio + ", so mark disk full");
            }
            cleanImmediately = true;
        } else if (physicRatio > diskSpaceCleanForciblyRatio) {/**#2*/
            cleanImmediately = true;
        } else {/**#3*/
            boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskOK();
            if (!diskok) {
                DefaultMessageStore.log.info("physic disk space OK " + physicRatio + ", so mark disk ok");
            }
        }
        if (physicRatio < 0 || physicRatio > ratio) {/**#4*/
            DefaultMessageStore.log.info("physic disk maybe full soon, so reclaim space, " + physicRatio);
            return true;
        }
    }
    

    1:物理使用率大於diskSpaceWarningLevelRatio(默認90%可通過參數設置),則會阻止新消息的插入

    2:物理使用率大於diskSpaceCleanForciblyRatio(默認85%,可設置),則過進行過期物理文件的刪除

    3:恢復磁盤可寫 配合 #1使用

    4:物理磁盤使用率小於diskMaxUsedSpaceRatio 表示磁盤使用正常

  2. manualDelete:預留,手工觸發,目前rocketmq暫未封裝

MappedFileQueue#deleteExpiredFileByTime

for (int i = 0; i < mfsLength; i++) {
    MappedFile mappedFile = (MappedFile) mfs[i];
    long liveMaxTimestamp = mappedFile.getLastModifiedTimestamp() + expiredTime;
    if (System.currentTimeMillis() >= liveMaxTimestamp || cleanImmediately) {
        if (mappedFile.destroy(intervalForcibly)) {
            files.add(mappedFile);
            deleteCount++;

            if (files.size() >= DELETE_FILES_BATCH_MAX) {
                break;
            }

            if (deleteFilesInterval > 0 && (i + 1) < mfsLength) {
                try {
                    Thread.sleep(deleteFilesInterval);
                } catch (InterruptedException e) {
                }
            }
        } else {
            break;
        }
    } else {
        //avoid deleting files in the middle
        break;
    }
}

image.png

從第一個文件開始遍歷,判斷該文件的最大存活時間(該文件的最後一次更新時間+文件的存活時間)小於 當前系統時間 或者 需要強制刪除文件(上面有講,哪些情況下強制刪除),則執行MappedFile#destroy 方法清除MappedFile佔用的相關資源,如果執行成功則將該文件加入待刪除文件列表中統一從磁盤中刪除。DELETE_FILES_BATCH_MAX 決定每次能夠刪除的文件個數上限、deleteFilesInterval連續清除兩個文件的時間間隔由該參數決定(deletePhysicFilesInterval)


4.總結-整體流程

  1. 開啓定時任務每10s掃描是否有文件需要刪除
  2. 有三種情況會進入刪除文件操作:到了deleteWhere指定的時間點(默認是凌晨4點)、磁盤不足、手動觸發
  3. 對於磁盤不足的情況,當磁盤使用率大於磁盤空間警戒線水位(默認是90%),會阻止消息寫入,當超過85%時會強制刪除文件(需要設置允許強制刪除參數,否者不生效),其他兩種情況都只能刪除過期的文件(文件最後更新時間+文件最大的存活時間 < 當前時間)
  4. 當被刪除的文件存在引用時,會有一個文件刪除緩存時間,在這段時間內,該文件不會被刪除,主要是留給引用該文件程序一些時間,當超過了文件刪除緩存時間後,每次都會將該文件的引用減少1000,直到減少小於等於0後才釋放該文件引用的相關資源,然後將該文件放入一個“文件刪除集合”中
  5. 一次連續刪除文件中間會存在一定的間隔,不會連續釋放文件相關的資源
  6. 一次連續刪除的文件和不大於10
  7. 將“文件刪除集合”中的文件從
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章