RocketMQ源码(十六)之文件清理

简介

  1. Broker文件清理主要清理CommitLog、ConsumeQueue、IndexFile
  2. CommitLog清理规则
    • 文件过期(默认72小时),且达到清理时间点(默认是凌晨4点),删除过期文件
    • 文件过期(默认72小时),且磁盘空间达到了75%(默认),删除过期文件
    • 磁盘已经达到上限(默认85%)的时候,则开始批量清理文件(无论是否过期),直到空间充足
    • 只删除到倒数第二个文件,不删除最后一个文件
  3. 若磁盘空间达到危险水位线(默认90%),出于保护自身的目的,broker会拒绝写入服务
  4. 清理CommitLog并不是一条一条的删除,而是对比MappedFile最后一条消息是否还在实效范围内,如果是则不会被清理,否则会被清理。除非当磁盘占用85%时,此时无论是否过期,会理解删除。清理完CommitLog后,获取到CommitLog最小的偏移量offset,然后将ConsumeQueue和IndexFile中最小的offset删除掉(同样也是删除文件)。

源码分析

  1. DefaultMessageStore#start启动时,会添加一些定时任务(调用DefaultMessageStore#addScheduleTask方法),其中有一个定时任务就是清理文件的。默认初始延迟60s,每10s执行一次

    this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
         
        @Override
        public void run() {
         
            DefaultMessageStore.this.cleanFilesPeriodically();
        }
    }, 1000 * 60, this.messageStoreConfig.getCleanResourceInterval(), TimeUnit.MILLISECONDS);
    
    private void cleanFilesPeriodically() {
         
      	// 清理CommitLog
        this.cleanCommitLogService.run();
      	// 清理ConsumeQueue和IndexFile
        this.cleanConsumeQueueService.run();
    }
    

CommitLog清理

  1. CleanCommitLogService用于清理CommitLog文件。此类的run方式被删除文件定时任务调用

    public void run() {
         
        try {
         
            //删除过期文件
            this.deleteExpiredFiles();
            // 重删挂起的文件,线程引用过期文件、内存映射清理失败,都可能导致删除失败
            // 判断第一个MappedFile是否可用
            // 可能上面的MappedFile销毁失败,只是设置了不可用,但是并没有销毁,此处重删。但是这里只是删除第一个?
            this.redeleteHangedFile();
        } catch (Throwable e) {
         
            DefaultMessageStore.log.warn(this.getServiceName() + " service has exception. ", e);
        }
    }
    
  2. CleanCommitLogService#deleteExpiredFiles

    • 文件保留时间,默认72小时,多个文件默认删除间隔100ms(为了避免影响磁盘性能)
    • 删除的触发条件有三个:到了删除时间、磁盘满了、手动删除(目前没看到哪里使用)
    private void deleteExpiredFiles() {
         
        int deleteCount = 0;
        //文件保留时间,默认72小时
        long fileReservedTime = DefaultMessageStore.this.getMessageStoreConfig().getFileReservedTime();
        //删除的时间间隔,默认100ms
        int deletePhysicFilesInterval = DefaultMessageStore.this.getMessageStoreConfig().getDeleteCommitLogFilesInterval();
        //
        int destroyMapedFileIntervalForcibly = DefaultMessageStore.this.getMessageStoreConfig().getDestroyMapedFileIntervalForcibly();
        //是否到删除时间,默认是04,凌晨4点
        boolean timeup = this.isTimeToDelete();
        //磁盘空间是否满了
        boolean spacefull = this.isSpaceToDelete();
        //TODO 手动删除文件次数是否大于0,目前没看到哪里使用到
        boolean manualDelete = this.manualDeleteFileSeveralTimes > 0;
    
        if (timeup || spacefull || manualDelete) {
         
    
            if (manualDelete)
                this.manualDeleteFileSeveralTimes--;
            // 开启强制清理(默认true)&& 立即清理
            boolean cleanAtOnce = DefaultMessageStore.this.getMessageStoreConfig().isCleanFileForciblyEnable() && this.cleanImmediately;
    
            log.info("begin to delete before {} hours file. timeup: {} spacefull: {} manualDeleteFileSeveralTimes: {} cleanAtOnce: {}",
                fileReservedTime,
                timeup,
                spacefull,
                manualDeleteFileSeveralTimes,
                cleanAtOnce);
            //过期时间默认是72小时,如果一个文件commitLog的数据文件在72小时内没有被修改过 那么就认为该文件已经过期了
            fileReservedTime *= 60 * 60 * 1000;
            //删除文件,通过mappedFileQueue来删除
            deleteCount = DefaultMessageStore.this.commitLog.deleteExpiredFile(fileReservedTime, deletePhysicFilesInterval,
                destroyMapedFileIntervalForcibly, cleanAtOnce);
            if (deleteCount > 0) {
         
            } else if (spacefull) {
         
                log.warn("disk space will be full soon, but delete file failed.");
            }
        }
    }
    
  3. 判断是否到时间,默认是凌晨四点,判断小时是否是当前小时

    private boolean isTimeToDelete() {
         
        // 默认是04,凌晨4点。多个时间使用;分号分隔
        String when = DefaultMessageStore.this.getMessageStoreConfig().getDeleteWhen();
        if (UtilAll.isItTimeToDo(when)) {
         
            DefaultMessageStore.log.info("it's time to reclaim disk space, " + when);
            return true;
        }
    
        return false;
    }
    
  4. 判断磁盘空间是否满了:磁盘占比配置,默认是75%,如果配置小于10,则按照10。如果配置大于95则按照95。大于75%,则返回磁盘空间满的状态。如果磁盘使用率大于85%,设置立即清理状态为true,表示无论是否72小时过期,都会删除。

    private final double diskSpaceWarningLevelRatio =
                Double.parseDouble(System.getProperty("rocketmq.broker.diskSpaceWarningLevelRatio", "0.90"));
    
    private final double diskSpaceCleanForciblyRatio =
                Double.parseDouble(System.getProperty("rocketmq.broker.diskSpaceCleanForciblyRatio", "0.85"));
    
    private boolean isSpaceToDelete() {
         
        // 磁盘空间占比默认是0.75,如果配置<10,按照10,如果配置>95,按照95
        double ratio = DefaultMessageStore.this.getMessageStoreConfig().getDiskMaxUsedSpaceRatio() / 100.0;
    
        cleanImmediately = false;
    
        {
         
            // CommitLog路径
            String storePathPhysic = DefaultMessageStore.this.getMessageStoreConfig().getStorePathCommitLog();
            // 返回此磁盘分区使用的占比
            double physicRatio = UtilAll.getDiskPartitionSpaceUsedPercent(storePathPhysic);
            // 如果磁盘使用率大于90%,就设置runningFlags标志位为磁盘满了的状态
            if (physicRatio > diskSpaceWarningLevelRatio) {
         
                boolean diskok = DefaultMessageStore.this.runningFlags.getAndMakeDiskFull();
                if (diskok) {
         
                    DefaultMessageStore.log.error("physic disk maybe full soon " + physicRatio <
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值