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
- Java實時讀取日誌檔案Java
- PHP如何快速讀取大檔案PHP
- mysqlbinlog 處理二進位制日誌檔案的工具MySql
- 利用外部表讀取告警日誌檔案
- 【轉】PHP如何快速讀取大檔案PHP
- SQL Server日誌檔案總結及日誌滿的處理SQLServer
- [zt] SQL Server日誌檔案總結及日誌滿的處理SQLServer
- Golang專案中讀取配置檔案Golang
- sql server日誌檔案總結及日誌滿的處理辦法SQLServer
- 從0寫一個Golang日誌處理包Golang
- sqlserver日誌檔案總結及充滿處理 (摘)SQLServer
- sqlserver日誌檔案總結及充滿處理(轉)SQLServer
- 日誌檔案過大清理
- 非歸檔下日誌檔案丟失的處理辦法
- 使用外部表讀日誌檔案
- 讀取檔案迴圈處理的兩種方法
- JavaScript檔案處理第二部分:檔案讀取JavaScript
- MATLAB快速讀取STL檔案Matlab
- [Golang]呼叫外部shell程式處理檔案Golang
- 水煮十三《——ora-16038日誌檔案錯誤處理
- nginx日誌處理Nginx
- ORACLE 告警日誌alert過大的處理Oracle
- Golang 超大檔案讀取的兩個方案Golang
- java 檔案處理 工具類Java
- python讀取大檔案Python
- Java高效讀取大檔案Java
- SQL Server 2005日誌檔案損壞的處理方法SQLServer
- node專案錯誤處理與日誌
- Python處理大檔案Python
- 使用Java處理大檔案Java
- Oracle DataGuard歸檔日誌丟失處理方法Oracle
- 清理tomcat日誌大的檔案Tomcat
- 網際網路金融專案——工作日誌(六)玩轉檔案讀取
- SQL Server事務日誌過大的處理SQLServer
- 檔案處理平臺後端Golang外包專案後端Golang
- golang 讀取切分儲存byte流檔案Golang
- 【Oracle日誌】- 日誌檔案重建Oracle