文件监控性能问题【BUG】

文件监控性能问题【BUG】

背景:JAVA写了一个文件夹目录监控的程序,使用的是org.apache.commons.io.monitor 包,项目稳定运行了一个月,现场反馈,文件夹数据处理越来越慢,等到数据推送到前端要好几分钟,于是开始了寻找问题的路程。

监控代码

之前写的文件监控代码

问题发现

我在ApplicationRunner的实现类中重写了run方法,打印了日志

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        log.info("监听开始");
        // 轮询间隔 1 秒
        long interval = TimeUnit.SECONDS.toMillis(1);
        // 创建过滤器
        IOFileFilter directories = FileFilterUtils.and(
                FileFilterUtils.directoryFileFilter(),
                HiddenFileFilter.VISIBLE);
        IOFileFilter files = FileFilterUtils.and(
                FileFilterUtils.fileFileFilter(),
                FileFilterUtils.suffixFileFilter(fileEnd));
        IOFileFilter filter = FileFilterUtils.or(directories, files);
        // 使用过滤器
        FileAlterationObserver observer = new FileAlterationObserver(new File(baseDataSyncDir), filter);
        observer.addListener(new FileMonitor());
        //创建文件变化监听器
        FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
        // 开始监控
        monitor.start();
        log.info("监听开始{}",baseDataSyncDir);
    }	

本地调试,秒打印两行日志,但是放到现场运行,这两行日志相差三分钟,在之后的fileCreate 监听中也是发现大概三分钟才能发现一批新数据,这就是导致数据推送不及时的原因。

在发现问题过后,我仔细想了下文件监控的原理,到底是怎么来监控文件的呢,找了下源码看了下,果然,是循环处理所有文件。FileAlterationObserver中的checkeNotify()方法,就是获取所有的文件,然后进行一个个的判断。

 public void checkAndNotify() {
        Iterator var1 = this.listeners.iterator();

        while(var1.hasNext()) {
            FileAlterationListener listener = (FileAlterationListener)var1.next();
            listener.onStart(this);
        }

        File rootFile = this.rootEntry.getFile();
        if (rootFile.exists()) {
            this.checkAndNotify(this.rootEntry, this.rootEntry.getChildren(), this.listFiles(rootFile));
        } else if (this.rootEntry.isExists()) {
            this.checkAndNotify(this.rootEntry, this.rootEntry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
        }

        Iterator var5 = this.listeners.iterator();

        while(var5.hasNext()) {
            FileAlterationListener listener = (FileAlterationListener)var5.next();
            listener.onStop(this);
        }

    }

分析问题

问题出现的原因:由于程序在处理了文件之后,并没有将文件进行删除处理,而是将数据移动到当前目录的子目录中,但是子目录依旧在程序监控的根目录下,这就导致根目录下的数据量越来越大,进而引发了项目文件监控处理一次需要三分钟,也就是说会随着文件数据量的逐渐增加,处理一次需要的时间也会逐渐增加,最终会导致程序崩溃。

解决方案

1.在处理完文件之后,将文件删除。

2.处理完文件之后,将文件移动到不在监控文件夹下

BUG感悟

不是所有的bug在本地都可以复现,在线上出现问题的时候,不要怀疑是偶然情况,预定难以解决的问题的时候,先大致分析下问题所在,找不到问题原因就打日志,缩小问题范围,结合源码进行分析。

posted @ 2021-01-19 11:43  喜中5000万  阅读(395)  评论(4编辑  收藏