Golang 快速讀取處理大日誌檔案工具
前段時間根據在站內看到的文章,做了翻譯並製作改進了易用工具,用於快速處理大日誌檔案 相關文章連結可以見 文章
工具地址在 這裡
本文翻譯並改進於 此文
當今世界的計算機系統每天會產生海量的日誌,但是這些日誌並不適合存入到資料庫中。因為這些資料都是不可變的,並且只用於資料分析和故常排除。因此大部分情況下這些日誌都會被存放在磁碟的檔案中。往往這些日誌檔案都會增長到 GB 級別,在需要對日誌和打點進行資料分析時,如何快速高效的讀取海量日誌檔案便成為了很影響工作效率的一件事。本文介紹一種使用 Golang 通過非同步 IO 快速讀取大日誌檔案的方法。
相關的工具程式碼在 Github 可以找到
Start
首先我們來開啟檔案。我們使用 Go 標準庫的 os.File 來處理所有檔案的 IO。
f, err := os.Open(fileName)
if err != nil {
fmt.Println("cannot able to read the file", err)
return
}
defer file.Close() //Do not forget to close the file
開啟檔案之後,我們有兩種方式來處理檔案:
- 一行一行的讀取檔案。這種方式減輕了記憶體的壓力,但是會在檔案 IO 上會費更多的時間
- 一次性將整個檔案讀入記憶體。這種方式會消耗掉很多記憶體但極大地提高了執行效率
鑑於我們的日誌檔案很大,可能會有幾個 GB 甚至十幾 GB,我們無法將整個檔案讀入到記憶體中,但是第一種方法同樣不太符合我們的需求,因為我們期望能在秒級內處理整個日誌檔案。 好在我們還有第三種方法,我們可以平衡兩種方法,將整個檔案按塊讀取到記憶體中,在 Go 中使用 bufio.NewReader() 就可以做到這一點。
r := bufio.NewReader(f)
for {
buf := make([]byte,4*1024) //the chunk size
n, err := r.Read(buf) //loading chunk into buffer
buf = buf[:n]
if n == 0 {
if err != nil {
fmt.Println(err)
break
}
if err == io.EOF {
break
}
return err
}
}
每當我們讀入了一個塊,我們就啟動一個 Goroutine 來併發的處理檔案塊,這樣上面的程式碼會變成:
//sync pools to reuse the memory and decrease the preassure on //Garbage Collector
linesPool := sync.Pool{New: func() interface{} {
lines := make([]byte, 500*1024)
return lines
}}
stringPool := sync.Pool{New: func() interface{} {
lines := ""
return lines
}}
slicePool := sync.Pool{New: func() interface{} {
lines := make([]string, 100)
return lines
}}
r := bufio.NewReader(f)
var wg sync.WaitGroup //wait group to keep track off all threads
for {
buf := linesPool.Get().([]byte)
n, err := r.Read(buf)
buf = buf[:n]
if n == 0 {
if err != nil {
fmt.Println(err)
break
}
if err == io.EOF {
break
}
return err
}
nextUntillNewline, err := r.ReadBytes('\n') //read entire line
if err != io.EOF {
buf = append(buf, nextUntillNewline...)
}
wg.Add(1)
go func() {
//process each chunk concurrently
//start -> log start time, end -> log end time
ProcessChunk(buf, &linesPool, &stringPool, &slicePool, start, end)
wg.Done()
}()
}
wg.Wait()
上面的程式碼在效率上有兩個優化點:
- sync.Pool 是一個高效的例項池,可以用於減輕 GC 的壓力。我們可以對不同的切片複用記憶體分配,這大大減少了記憶體上的壓力。
- 使用了 Go Routines 來併發處理檔案塊,這樣可以進行非同步 IO,提高了 CPU 的利用率,加快了整個檔案的處理速度
最後我們來實現處理函式
//sync pools to reuse the memory and decrease the preassure on //Garbage Collector
linesPool := sync.Pool{New: func() interface{} {
lines := make([]byte, 500*1024)
return lines
}}
stringPool := sync.Pool{New: func() interface{} {
lines := ""
return lines
}}
slicePool := sync.Pool{New: func() interface{} {
lines := make([]string, 100)
return lines
}}
r := bufio.NewReader(f)
var wg sync.WaitGroup //wait group to keep track off all threads
for {
buf := linesPool.Get().([]byte)
n, err := r.Read(buf)
buf = buf[:n]
if n == 0 {
if err != nil {
fmt.Println(err)
break
}
if err == io.EOF {
break
}
return err
}
nextUntillNewline, err := r.ReadBytes('\n') //read entire line
if err != io.EOF {
buf = append(buf, nextUntillNewline...)
}
wg.Add(1)
go func() {
//process each chunk concurrently
//start -> log start time, end -> log end time
ProcessChunk(buf, &linesPool, &stringPool, &slicePool, start, end)
wg.Done()
}()
}
wg.Wait()
上面的程式碼處理 16GB 的檔案耗時大概在 25S 左右
多元化相容處理
在實際的生產環境中,我們肯定不會任由日誌檔案瘋狂增長下去,一般情況下都會將日誌檔案進行切割和壓縮。日誌檔案往往都會按照一定名稱格式來儲存,並且歸檔為 .gz 型別的檔案。因此我在原本的程式碼基礎上增加了一些定製內容,包括
- 指定檔名稱格式化,支援多檔案處理。(多檔案處理採用了序列方式,實測並行檔案處理在非同步 IO 上優化不大,且會佔用更多的記憶體)
- 支援 gz 檔案讀取
- 行處理函式可定製,自由定製輸出格式
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- java讀取大檔案並處理Java
- mysqlbinlog 處理二進位制日誌檔案的工具MySql
- Java實時讀取日誌檔案Java
- Golang專案中讀取配置檔案Golang
- 從0寫一個Golang日誌處理包Golang
- MATLAB快速讀取STL檔案Matlab
- 日誌檔案過大清理
- python讀取大檔案Python
- [Golang]呼叫外部shell程式處理檔案Golang
- java 檔案處理 工具類Java
- golang 讀取切分儲存byte流檔案Golang
- Golang 超大檔案讀取的兩個方案Golang
- node專案錯誤處理與日誌
- python如何讀取大檔案Python
- Oracle DataGuard歸檔日誌丟失處理方法Oracle
- Java讀取Json檔案工具類JavaJSON
- 檔案處理平臺後端Golang外包專案後端Golang
- Python 如何處理大檔案Python
- js讀取excel檔案,繪製echarts圖形---資料處理JSExcelEcharts
- Golang 讀、寫檔案Golang
- 本地檔案包含之包含日誌獲取webshellWebshell
- php讀取大檔案詳解PHP
- uPDF-功能強大的PDF檔案處理小工具
- shell日誌顏色處理
- orbeon form 的日誌處理ORBORM
- syslog強大而安全的日誌處理系統
- ORA-00279異常處理_offline資料檔案缺失日誌檔案問題一鍵修復
- 如何將日誌檔案和二進位制檔案快速匯入HDFS?
- Python生成器讀取大檔案Python
- (slam工具)1檔案讀取和儲存SLAM
- Java讀取properties配置檔案工具包Java
- crfclust.bdb檔案過大處理CRF
- 【MySQL日誌】MySQL日誌檔案初級管理MySql
- node錯誤處理與日誌
- DATAGUARD中手工處理日誌GAP
- java專案日誌配置檔案Java
- python讀取大檔案的幾種方法Python
- Golang對檔案讀寫操作Golang