文件監控性能問題【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在本地都可以復現,在線上出現問題的時候,不要懷疑是偶然情況,預定難以解決的問題的時候,先大致分析下問題所在,找不到問題原因就打日志,縮小問題范圍,結合源碼進行分析。