持續監控檔案變化時使用filepath遇坑,填坑記....持續更新

huhuyou2發表於2018-01-18

最近在做個處理日誌的功能,首先就是要把日誌檔案的變化掃描出來,之前看過相關實現方法,有如下兩種主流的方式:

//第一種
Listfunc(path string, f os.FileInfo, err error){}
filepath.Walk(path, Listfunc){}

//第二種
files,_ := ioutil.ReadDir(path)
for file := range files{
    if file.IsDir(){

    }else{

    }
}

我在實際開發中面對的是不斷增加的多個檔案下的多份日誌檔案,唯一的判定標識是日誌檔案字尾,整個日誌空間不到800M左右會遠端轉儲備份。

----x1
   -x1_標識.log  (最大10M,10M後轉儲成帶時間戳的日誌檔案)
   -x1_標識_2018-1-18.log
----x2
   -x2_標識.log

這樣的場景下,我選擇了loop filepath.Walk的方案,在loop頻率設定3分鐘的情況下穩定跑了大概2周了。可是最近幾天業務量大了,為了更快的得到日誌變化的內容,把loop頻率設定成了3s。在跑了1個晚上後出現了panic。

於是,我使用pprof檢視了3s場景下半天內的heap資料,發現heap持續增長。使用pprof -alloc_space檢視了下記憶體分配情況,顯示如下:

ROUTINE ======================== os.(*File).readdirnames in C:/Go/src/os/dir_unix.go
    4.24GB     4.60GB (flat, cum) 56.78% of Total
         .          .     43:}
         .          .     44:
         .          .     45:func (f *File) readdirnames(n int) (names []string, err error) {
         .          .     46:   // If this file has no dirinfo, create one.
         .          .     47:   if f.dirinfo == nil {
      25MB       25MB     48:           f.dirinfo = new(dirInfo)
         .          .     49:           // The buffer must be at least a block long.
    2.91GB     2.91GB     50:           f.dirinfo.buf = make([]byte, blockSize)
         .          .     51:   }
         .          .     52:   d := f.dirinfo
         .          .     53:
         .          .     54:   size := n
         .          .     55:   if size <= 0 {
         .          .     56:           size = 100
         .          .     57:           n = -1
         .          .     58:   }
         .          .     59:
    1.31GB     1.31GB     60:   names = make([]string, 0, size) // Empty with room to grow.
         .          .     61:   for n != 0 {
         .          .     62:           // Refill the buffer if necessary

看來這種遍歷檔案路徑的方式在資源消耗上存在很大問題。

突然想起來謝大Beego配套的Bee工具貌似也有檔案變化感知的功能,準備嘗試其中的fsnotify來解決我的問題,明天有會議,計劃週六動手試試。有結果了繼續更新。

相關文章