rocketmq定时清理commitlog文件源码分析

rocketmq的配置参数

// 何时触发删除文件, 默认凌晨4点删除文件
@ImportantField
private String deleteWhen = "04";

猜想rocketmq会起一个一天执行一次的定时任务。
但看了代码发现并不是这样。

在存储服务启动时,启动如下的定时任务:

private void addScheduleTask() {
    // 定时删除过期文件
    this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            DefaultMessageStore.this.cleanFilesPeriodically();
        }
    }, 1000 * 60, this.messageStoreConfig.getCleanResourceInterval(), TimeUnit.MILLISECONDS);

getCleanResourceInterval 默认是10s。

没10s执行CleanCommitLogService,清理过期文件。

删除时,有三个判断条件:
if (timeup || spacefull || manualDelete)
timeup就是到了定时时间点的判断。
spacefull是磁盘满的判断。
manualDelete是手动触发删除的判断。

判断定时时间的逻辑简单。
判断磁盘的,需要注意。
得到磁盘利用率的方法:
拿到commitlog的文件路径

long totalSpace = file.getTotalSpace();
long freeSpace = file.getFreeSpace();

这样就可以得到磁盘空间的信息。

需要注意的是,有三个磁盘利用率的配置。

  1. diskMaxUsedSpaceRatio。我们设置的磁盘最大利用率。默认是75
  2. DiskSpaceWarningLevelRatio。磁盘空间警戒水位,超过,则停止接收新消息(出于保护自身目的)默认是90
  3. DiskSpaceCleanForciblyRatio。磁盘空间强制删除文件水位。默认是85

逻辑是:
当磁盘水位高于DiskSpaceWarningLevelRatio。会触发一个getAndMakeDiskFull操作,标记mq运行状态为磁盘满。并触发一次System.gc()。
标记cleanImmediately为true。

当磁盘水位高于DiskSpaceCleanForciblyRatio。标记cleanImmediately为true。

当上面两个条件不达到,执行getAndMakeDiskOK,将运行状态标记为ok。因为之前可能执行过getAndMakeDiskFull操作,所以这里要再执行下标记OK的操作,这就可以再次写了。也就是说如果之前达到过full状态,至少10s钟不能写,要等下一次执行周期改回ok的状态。

最后判断下,如果大于diskMaxUsedSpaceRatio。返回true。
所以我们设置的值不要大于85。

下面还有一次对storePathRootDir路径下磁盘空间的判断,逻辑一样。

下面是源码:

        /**
         * 是否可以删除文件,空间是否满足
         */
        private boolean 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) {
                    boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskFull();
                    if (diskok) {
                        DefaultMessageStore.log.error("physic disk maybe full soon " + physicRatio
                                + ", so mark disk full");
                        System.gc();
                    }

                    cleanImmediately = true;
                }
                else if (physicRatio > DiskSpaceCleanForciblyRatio) {
                    cleanImmediately = true;
                }
                else {
                    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) {
                    DefaultMessageStore.log.info("physic disk maybe full soon, so reclaim space, "
                            + physicRatio);
                    return true;
                }
            }

            // 检测逻辑文件磁盘空间
            {
                String storePathLogics =
                        StorePathConfigHelper.getStorePathConsumeQueue(DefaultMessageStore.this
                            .getMessageStoreConfig().getStorePathRootDir());
                double logicsRatio = UtilAll.getDiskPartitionSpaceUsedPercent(storePathLogics);
                if (logicsRatio > DiskSpaceWarningLevelRatio) {
                    boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskFull();
                    if (diskok) {
                        DefaultMessageStore.log.error("logics disk maybe full soon " + logicsRatio
                                + ", so mark disk full");
                        System.gc();
                    }

                    cleanImmediately = true;
                }
                else if (logicsRatio > DiskSpaceCleanForciblyRatio) {
                    cleanImmediately = true;
                }
                else {
                    boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskOK();
                    if (!diskok) {
                        DefaultMessageStore.log.info("logics disk space OK " + logicsRatio
                                + ", so mark disk ok");
                    }
                }

                if (logicsRatio < 0 || logicsRatio > ratio) {
                    DefaultMessageStore.log.info("logics disk maybe full soon, so reclaim space, "
                            + logicsRatio);
                    return true;
                }
            }

            return false;
        }
        
  1. 继续说CleanCommitLogService
    达到匹配的条件,开始删除。

    // 是否立刻强制删除文件
    boolean cleanAtOnce = DefaultMessageStore.this.getMessageStoreConfig().isCleanFileForciblyEnable() && this.cleanImmediately;
    

isCleanFileForciblyEnable默认是true。所以cleanImmediately为true时,即磁盘>85,将开始强制删除文件。

// 删除多个CommitLog文件的间隔时间(单位毫秒)
private int deleteCommitLogFilesInterval = 100;
// 强制删除文件间隔时间(单位毫秒)
private int destroyMapedFileIntervalForcibly = 1000 * 120;

执行下面的源码:

/**
 * 根据文件过期时间来删除物理队列文件
 */
public int deleteExpiredFileByTime(//
        final long expiredTime, //
        final int deleteFilesInterval, //
        final long intervalForcibly,//
        final boolean cleanImmediately//
) {
    Object[] mfs = this.copyMapedFiles(0);

    if (null == mfs)
        return 0;

    // 最后一个文件处于写状态,不能删除
    int mfsLength = mfs.length - 1;
    int deleteCount = 0;
    List<MapedFile> files = new ArrayList<MapedFile>();
    if (null != mfs) {
        for (int i = 0; i < mfsLength; i++) {
            MapedFile mapedFile = (MapedFile) mfs[i];
            long liveMaxTimestamp = mapedFile.getLastModifiedTimestamp() + expiredTime;
            if (System.currentTimeMillis() >= liveMaxTimestamp//
                    || cleanImmediately) {
                if (mapedFile.destroy(intervalForcibly)) {
                    files.add(mapedFile);
                    deleteCount++;

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

                    if (deleteFilesInterval > 0 && (i + 1) < mfsLength) {
                        try {
                            Thread.sleep(deleteFilesInterval);
                        }
                        catch (InterruptedException e) {
                        }
                    }
                }
                else {
                    break;
                }
            }
        }
    }

    deleteExpiredFile(files);

    return deleteCount;
}

可以看到是在for循环中用时间判断,或者是强制删除。但是删除的个数有限制,默认最多一次删除10个。
然后等下次执行周期再删。

copyMapedFiles时,用的读写锁,加一下读锁。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容