【Go】使用压缩文件优化io (二) (3)

读取时:

avg-cpu: %user %nice %system %iowait %steal %idle 80.66 0.00 4.83 14.50 0.00 0.00 Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util vda 0.00 0.00 6.20 0.20 0.06 0.00 20.00 0.01 1.69 1.71 1.00 0.62 0.40 vdb 0.00 6.80 390.40 19.20 118.78 0.23 595.04 74.87 190.55 197.95 40.08 1.85 75.90

通过 iostat 结果分析,下载时 io 阻塞和优化前波动不是很大,读取时的 io 优化已经非常好了,iowait 从 92.19% 降低到 14.5% ,CPU 更多的任务用来处理解压缩日志,而不是处理 io 阻塞。

优化方案二

本来优化到上面的效果已经非常满意了,不过既然开始做优化就不能草草结束了,仔细思考业务场景,需要 本地 lzo 文件?重新处理日志的频率高吗?本地 lzo 日志清理方便吗?

通过上面的几个问题发现,除非程序出现问题或者数据存储出现故障,否者极少需要重新处理日志,一年里面这种情况也是极少的,甚至不会发生。

那么思考一下,不下载日志,直接读取网络数据流,实现边下边解压边读取,这样岂不是没有 io 了吗?

优化后日志处理流程:

获取待处理文件列表

拉取 OSS 日志,在内存中解压并读取分析日志

业务处理……

导入到数据仓储中

具体实现如下:

package main import ( "fmt" "sync" "time" ".../pkg/aliyun_oss" // 虚假的包 "github.com/cyberdelia/lzo" ) func main() { var oss *aliyun_oss.AliyunOSS // 对接阿里云 OSS,需要自行封装 files := list() // 这是一个虚构的方法,用来获取待处理的文件列表 fmt.Printf("待处理文件数量:%d\n", len(files)) start := time.Now() defer func(t time.Time) { fmt.Printf("共耗时:%0.6f\n", time.Now().Sub(t).Seconds()) }(start) n := 20 var wg sync.WaitGroup c := make(chan string) wg.Add(n) for i := 0; i < n; i++ { go func() { defer wg.Done() for { f, ok := <-c if !ok { return } r1, err := oss.GetObject(f) if err != nil { panic(err) } r, err := lzo.NewReader(r1) if err != nil { panic(err) } Read(r) r.Close() r1.Close() } }() } for _, f := range files { c <- f } close(c) wg.Wait() fmt.Printf("读取文件耗时:%0.6f\n", time.Now().Sub(start).Seconds()) }

优化后只有一个流程了,代码简洁了不少,看看效率如何吧!

程序运行结果如下:

待处理文件数量:432 读取文件耗时:285.993661 共耗时:285.993717

天啊发生了什么,我使劲擦了擦眼睛,太不可思议了,居然只消耗了下载日志的耗时,较上一个方案总耗时从 418.942862 降低到 285.993717,提升了近 2 倍的效率,让我们看看上个方案下载文件耗时 286.146603 ,而新方案总耗时是 285.993717 居然只用了上个优化版本的下载时间,究竟发生了什么?

通过 iostat -m -x 5 10000 分析结果如下:

avg-cpu: %user %nice %system %iowait %steal %idle 43.73 0.00 9.64 0.31 0.00 46.32 Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util vda 0.00 1.20 4.40 3.80 0.02 0.03 10.93 0.01 1.49 0.59 2.53 0.71 0.58 vdb 0.00 6.80 0.00 24.60 0.00 0.27 22.83 0.02 0.84 0.00 0.84 0.28 0.68

通过 iostat 结果分析,在程序运行期间没有任何 io 开销,CPU 居然还有一半的空闲,前面两个版本 CPU 是没有空闲的啊,由此看来之前 CPU 更多的消耗在 io 阻塞上了,并没有用来处理业务逻辑。

由此来看也就不足为奇了,为啥优化后只需要下载日志的时间就能处理完所有日志了,没有了 io 阻塞,CPU 更多了用来处理业务,把之前下载时写文件 io 的耗时,用来解压缩数据,读取数据,且还有更多的空闲,跑出这样的结果也就很正常了。

总结

从优化前耗时 1375.187261 秒到 285.993717 秒,性能提升 80%, 从 iowait 92.19% 到 0.31% 提升近 100%,从没有任何 CPU 空闲到有一半空闲,这个过程中有很多值得总结的事情。

io 对性能的影响非常大,对 CPU 占用非常严重,导致 CPU 处理业务逻辑的时间片非常少。从 io 转移到 CPU 对性能提升非常明显。CPU 计算效率十分的高,从 io 密集到密集计算,只要符合业务场景,往往能给我们带来意想不到的效果。

往往优化业务并不需要十分高大上的技术,只是转变一下思路,不仅代码更少,且程序更简短、好维护、逻辑更清晰。

一定要结合实际业务场景进行思考,减少理所当然和业务无关的中间环节,往往就可以极大的提升程序效率。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzxdw.html