背景:JAVA写了一个文件夹目录监控的程序,使用的是org.apache.commons.io.monitor 包,项目稳定运行了一个月,现场反馈,文件夹数据处理愈来愈慢,等到数据推送到前端要好几分钟,因而开始了寻找问题的路程。html
我在ApplicationRunner的实现类中重写了run方法,打印了日志java
@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 监听中也是发现大概三分钟才能发现一批新数据,这就是致使数据推送不及时的缘由。apache
在发现问题事后,我仔细想了下文件监控的原理,究竟是怎么来监控文件的呢,找了下源码看了下,果真,是循环处理全部文件。FileAlterationObserver中的checkeNotify()方法,就是获取全部的文件,而后进行一个个的判断。app
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); } }
问题出现的缘由:因为程序在处理了文件以后,并无将文件进行删除处理,而是将数据移动到当前目录的子目录中,可是子目录依旧在程序监控的根目录下,这就致使根目录下的数据量愈来愈大,进而引起了项目文件监控处理一次须要三分钟,也就是说会随着文件数据量的逐渐增长,处理一次须要的时间也会逐渐增长,最终会致使程序崩溃。ide
1.在处理完文件以后,将文件删除。性能
2.处理完文件以后,将文件移动到不在监控文件夹下this
不是全部的bug在本地均可以复现,在线上出现问题的时候,不要怀疑是偶然状况,预约难以解决的问题的时候,先大体分析下问题所在,找不到问题缘由就打日志,缩小问题范围,结合源码进行分析。调试