Golang 按行解析日志测试 ldetool

比较早的时候写过一篇 Python Golang 解析web日志正则一例 当时发现 Golang的正则模块性能不是很好。最近在逛 reddit的时候发现了这样一篇文章 Fast log parsing with Go ,文中提到了一个基于行做半结构化解析的库ldetool, 于是又做了一些尝试和学习。

ldetool 这个工具更像一个DSL,通过一种语法来写解析的语法,然后通过 ldetool generate 命令来生成 golang 代码,这个代码就是针对某中格式单行的解析方法,详细的教程大家可以参考 https://github.com/sirkon/ldetool/blob/master/README.md ,下面是一个简单的测试过程的记录。

测试的环境 Mac Pro 8G4Core,粗略的看下性能,并不严谨

ldetool

安装

通过 go get就可以安装, 安装之后就是个命令

▶ go version
go version go1.11 darwin/amd64

go get -u github.com/sirkon/ldetool

▶ ldetool -v
ldetool version 0.0.0

场景

测试的样本是类似nginx的access log文件,格式如下

27.154.70.117 - - [20/Nov/2018:20:23:56 +0800] 2 "GET http://7img1.tianlaikge.com/tv/homeimage/201709/shengridangao.zip HTTP/1.1" 200 842186 841382 "-" "-" "Dalvik/2.1.0 (Linux; U; Android 7.1.2; vivo Y79A Build/N2G47H)" "-" 219082621 "HIT" 27.159.73.35

测试需求,解析30M左右的日志文件,大概12w行,计算总流量(流量字段为 842186)

分析

这种日志文件有几个特点

  • 每个记录就是一行文件
  • 虽然是文本,但是不是完全的无结构,算半结构化
  • 上下行基本无关,可以并行处理

通常的解析方案

  • 使用正则表达式(后面有个python版本的使用正则来分析)
  • 使用split方法,根据特征分隔符来分割,例如空格,双引号
  • 使用DSL,本质还是类似split,不过是通过代码生成器自动生成解析代码(上面提到的 ldetool 命令啦)

测试

源代码在 https://github.com/orangle/snippets/tree/master/golang/log_parse ,主要是对比split方式和ldetool生成的代码的性能(因为之前测试regex效果并不好,这里没有加入测试)

直接执行函数,使用 time 来测量的结果(多次测试下来,下面两个算是平均值)

# split
▶ time go run main.go nginx_lde.go
total:  96130191409
go run main.go nginx_lde.go  1.80s user 0.25s system 106% cpu 1.914 total

# ldetool
▶ time go run main.go nginx_lde.go
total:  96130191409
go run main.go nginx_lde.go  1.36s user 0.23s system 108% cpu 1.464 total

使用 golang test benckmark 测量的结果

▶ go test -bench=. -benchmem
total:  96130191409
goos: darwin
goarch: amd64
pkg: log_parse
BenchmarkSplit-4     	       1	1549334472 ns/op	512189744 B/op	 1629989 allocs/op
total:  96130191409
BenchmarkLdetool-4   	       1	1052007947 ns/op	 2996064 B/op	   24805 allocs/op
PASS
ok  	log_parse	2.608s

总的来看,ldetool还是能快40~50%的,内存使用和内存分配更是少了很多。

Python

之后我还做了个同样样本的Python测试,主要是正则表达式和split方式的对比,也可以参照golang的结果对比。

代码在 https://github.com/orangle/snippets/tree/master/python/regex_vs_split

python re, re没有 compile

▶ python regex_vs_split.py
total bytes: 96130099518 cost: 5.805 qps: 92174.132

python re, re compile之后

▶ python regex_vs_split.py
total bytes: 96130099518 cost: 5.324 qps: 100500.519

python split 之后分析

▶ python regex_vs_split.py
total bytes: 96130191409 cost: 3.957 qps: 135215.152

这样看起来 split要比 regex 快一些,但是比golang又慢蛮多的。

End

下次在遇到这种需求,可以尝试下 ldetool

你可能感兴趣的:(Golang)