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

下载时:

avg-cpu: %user %nice %system %iowait %steal %idle 7.85 0.00 16.44 11.24 0.00 64.48 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 80.40 7.80 8.98 0.04 209.36 0.40 4.57 4.64 3.77 0.50 4.44 vdb 1.40 761.20 247.60 264.00 14.70 60.92 302.72 9.17 17.92 10.36 25.00 0.52 26.52

解压时:

avg-cpu: %user %nice %system %iowait %steal %idle 8.54 0.00 8.33 68.39 0.00 14.74 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 3.40 11.80 0.01 0.05 8.95 0.30 20.03 0.41 25.68 0.55 0.84 vdb 0.00 22037.80 107.80 243.20 26.45 107.01 778.71 83.52 236.68 74.31 308.65 2.52 88.54

读取时:

avg-cpu: %user %nice %system %iowait %steal %idle 2.74 0.00 5.07 92.19 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 2.40 3.80 23.60 0.01 0.14 11.85 0.12 4.48 1.95 4.89 0.33 0.90 vdb 1.80 4.60 347.20 6.20 139.97 0.08 811.60 126.62 358.04 360.79 203.48 2.83 100.00

通过 iostat 结果可以看出,在解压和读取日志时 io 阻塞比较严重,且运行时间较长,下载时 io 阻塞也存在,但还可以接受,通过下面两个方案逐渐消除掉 io。

优化方案一

优化前的方案反应出在解压和读取日志时 io 阻塞比较严重,那么是否可以通过读取 lzo 压缩文件,以此来消除解压缩日志耗时太大、io 太高的问题呢?并且读取 lzo 压缩文件远比解压后文件小,来降低读取日志耗时太大、io 太高的问题呢?

优化后日志处理流程:

获取待处理文件列表

拉取 OSS 日志到本地磁盘 (压缩文件)

读取压缩日志数据

业务处理……

导入到数据仓储中

package main import ( "fmt" "os" "path/filepath" "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 } if _, err := os.Stat(f); err == nil { return } else if !os.IsNotExist(err) { panic(err) } dir := filepath.Dir(f) err := os.MkdirAll(dir, 0755) if err != nil { panic(err) } err = oss.GetObjectToFile(f, f) if err != nil { panic(err) } } }() } for _, f := range files { c <- f } close(c) wg.Wait() fmt.Printf("下载文件耗时:%0.6f\n", time.Now().Sub(start).Seconds()) start = time.Now() c = make(chan string) wg.Add(n) for i := 0; i < n; i++ { go func() { defer wg.Done() for { file, ok := <-c if !ok { return } f, err := os.Open(file) if err != nil { panic(err) } r, err := lzo.NewReader(f) if err != nil { panic(err) } Read(r) r.Close() f.Close() } }() } for _, f := range files { c <- f } close(c) wg.Wait() fmt.Printf("读取文件耗时:%0.6f\n", time.Now().Sub(start).Seconds()) }

这个方案消除了解压缩日志,并且直接读取压缩日志,使用 github.com/cyberdelia/lzo 包对压缩文件数据流进行边读取边解压,这次不用单独封装新的方法了,直接使用 lzo 包中的接口即可。

程序运行结果如下:

待处理文件数量:432 下载文件耗时:286.146603 读取文件耗时:132.787345 共耗时:418.942862

这个方案效果非常明显,总耗时从 1375.187261 降低到 418.942862 提升了 3 倍的效率,不仅消除了压缩的时间,还大大缩短了读取文件耗时,成果显著。

通过 iostat -m -x 5 10000 分析各个阶段结果如下:

下载时:

avg-cpu: %user %nice %system %iowait %steal %idle 5.08 0.00 13.24 29.34 0.00 52.33 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 2.80 1.40 11.80 0.01 0.07 12.00 0.02 1.85 1.14 1.93 0.18 0.24 vdb 0.00 17207.60 0.60 212.40 0.00 75.06 721.74 55.81 236.34 84.33 236.77 2.49 53.14

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

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