bingoohuang/blog

认知纠偏:50 G 的 ZIP 包要 50 G 的内存来解?

Opened this issue · 1 comments

缘起

那天,有一小哥虔诚的来问我,说他不小心在客户那边有一个 50 G 的 ZIP 包(客户实现打好的),需要在网络上传走,可是找不到特那么大的 50 G 的内存,咋办?

我有点“吓尿”了,我大概知道了,这小哥估计想是把整个文件,囫囵吞枣一样,一口吃进内存,然后再进行一些处理吧!

详细了解后,他还真是这么干的。他还写了一个测试程序,用了个 10M 的 zip 包做测试数据文件,还用读文件一行一行读接口去读,说竟然还读出来了。然后想去玩 50 G的包,然后就 OOM 了。

听完后一行一行的读后,我心理就默默的疑问,非文本文件也用一行一行读,难道他精通 Unix/Linux 哲学?Unix/Linux 哲学中的第5条:使用纯文本文件来存储数据 。

首先,度娘一下,ZIP 包的结构,了解一下大概是什么样子,如下所示,大概知道,还是一个文件写一块的嘛(我设计也得这么玩啊),流式写,磁盘缓冲写,估计几 M 内存就可以了。

image

其次,测试一下嘛,幸好我本机“收藏”了一些大的图片文件,小的 1 M,大的 100 M,用来 zip 一下,以及 unzip 一下,观察一下占用内存嘛。

wecom-temp-7672d1fd468f9cec734bf7ac2a0afb15

wecom-temp-facf7bafaca774542a834fef3059abd1

生成 1.7 G 的ZIP 和解开 ZIP,都不超过 2 M 内存。

实锤

计算机最大的一个好处,就是能够通过实验来实证一些自己的想法对不对。马上动手用 GO 语言自己造一个 ZIP 打包解包的小轮子,在解压缩的时候,顺便打印一下自己所占用的内存。代码在这里

打包跑一下,看看是不是内存随着文件大小变化而变化。

$ gg-zip bizhi
2022/01/24 11:01:08 adding bizhi/.DS_Store size: 12.3kB
2022/01/24 11:01:08 RSS: 2.8MB
2022/01/24 11:01:08 adding bizhi/.goup-files/246.png size: 96.9MB
2022/01/24 11:01:11 RSS: 3.6MB
2022/01/24 11:01:11 adding bizhi/246.png size: 96.9MB
2022/01/24 11:01:13 RSS: 3.7MB
2022/01/24 11:01:13 adding bizhi/247.png size: 16.1MB
2022/01/24 11:01:14 RSS: 3.8MB
2022/01/24 11:01:14 adding bizhi/4.jpg size: 1.2MB
2022/01/24 11:01:14 RSS: 3.8MB
2022/01/24 11:01:14 adding bizhi/壁纸精选 (156).png size: 12.4MB
2022/01/24 11:01:14 RSS: 3.9MB
2022/01/24 11:01:51 adding bizhi/壁纸精选 (234).png size: 12.7MB
2022/01/24 11:01:51 RSS: 7.8MB
2022/01/24 11:01:57 adding bizhi/壁纸精选 (245).png size: 26.5MB
2022/01/24 11:01:58 RSS: 8.1MB
2022/01/24 11:01:58 complete zip dir bizhi, output bizhi.zip

解包一下,再次,看看,是不是内存随着文件大小变化而变化。

2022/01/24 11:07:04 unzip bizhi/.DS_Store size: 12.3kB
2022/01/24 11:07:04 RSS: 2.7MB
2022/01/24 11:07:04 unzip bizhi/.goup-files/246.png size: 96.9MB
2022/01/24 11:07:05 RSS: 8.6MB
2022/01/24 11:07:05 unzip bizhi/246.png size: 96.9MB
2022/01/24 11:07:07 RSS: 8.9MB
2022/01/24 11:07:07 unzip bizhi/247.png size: 16.1MB
2022/01/24 11:07:07 RSS: 9.1MB
2022/01/24 11:07:07 unzip bizhi/4.jpg size: 1.2MB
2022/01/24 11:07:27 unzip bizhi/壁纸精选 (240).png size: 15.6MB
2022/01/24 11:07:27 RSS: 9.8MB
2022/01/24 11:07:27 unzip bizhi/壁纸精选 (241).png size: 12.3MB
2022/01/24 11:07:27 RSS: 9.8MB
2022/01/24 11:07:27 unzip bizhi/壁纸精选 (242).png size: 35.5MB
2022/01/24 11:07:28 RSS: 9.8MB
2022/01/24 11:07:28 unzip bizhi/壁纸精选 (243).png size: 13.3MB
2022/01/24 11:07:28 RSS: 9.8MB
2022/01/24 11:07:28 unzip bizhi/壁纸精选 (244).png size: 21.6MB
2022/01/24 11:07:28 RSS: 9.8MB
2022/01/24 11:07:28 unzip bizhi/壁纸精选 (245).png size: 26.5MB
2022/01/24 11:07:28 RSS: 9.8MB
2022/01/24 11:07:28 complete unzip bizhi.zip

可以看到,最大单个文件是 97 M,ZIP 打包内存没超过 8M,ZIP 解包内存不超过10M。实锤了之前的推测。

审视

让我们再次回归一下问题,探讨一下问题的本源。

我们是需要把一个 ZIP 包通过网络传输到另外一个地方。假设不是 ZIP 包,而是 TAR.GZ 包,或者其它文件呢。

本质上我们 要解决的不是解包问题,而是担心大文件在传输过程中由于网络问题,导致失败,重新上传时,又要重头再来的问题。所以我们本质上,需要解决的是大文件的 断点续传问题,这个才是抓住了问题的本质。

利用闲暇,可以找点资料,自己再造一个轮子吧,把文件拆分成一个个小块(比如10M)一个块,然后分块上传。每块上传前,先验证校验码是否一致,如果一致,说明这部分已经上传好了,不需要重新上传了。即使客户端中断,或者服务端中断,都可以实现以块为单位的断点续传了。

image

服务端启动

$ goup
2022/01/23 18:45:25 Listening on 2110
2022/01/24 11:19:16 recv file 246.png with session BEA87B882BC3B562, range bytes 0-10485760/96894303
2022/01/24 11:19:30 recv file 246.png with session BEA87B882BC3B562, range bytes 10485760-20971520/96894303
2022/01/24 11:19:44 recv file 246.png with session BEA87B882BC3B562, range bytes 20971520-31457280/96894303
2022/01/24 11:20:00 recv file 246.png with session BEA87B882BC3B562, range bytes 31457280-41943040/96894303
2022/01/24 11:20:13 recv file 246.png with session BEA87B882BC3B562, range bytes 41943040-52428800/96894303
2022/01/24 11:20:27 recv file 246.png with session BEA87B882BC3B562, range bytes 52428800-62914560/96894303
2022/01/24 11:20:43 recv file 246.png with session BEA87B882BC3B562, range bytes 62914560-73400320/96894303
2022/01/24 11:20:59 recv file 246.png with session BEA87B882BC3B562, range bytes 73400320-83886080/96894303
2022/01/24 11:21:13 recv file 246.png with session BEA87B882BC3B562, range bytes 83886080-94371840/96894303
2022/01/24 11:21:16 recv file 246.png with session BEA87B882BC3B562, range bytes 94371840-96894303/96894303

客户端对接发送

$ ls -hal 246.png    
-rw-r--r--  1 bingoobjca  staff    92M  1 24 11:07 246.png
$ goup -u a.b.c:2110 -f 246.png
2022/01/24 11:18:57 Upload BEA87B882BC3B562 started: 246.png
92.41 MiB / 92.41 MiB [-------------------------------------------] 100.00% 689.56 KiB p/s
2022/01/24 11:21:14 Upload BEA87B882BC3B562 complete: 246.png

再次执行,非常的快,因为文件没有任何部分重新传送:

$ goup -u a.b.c:2110 -f 246.png                    
2022/01/24 11:43:50 Upload DCF74FE9C195C627 started: 246.png
92.41 MiB / 92.41 MiB [----------------------------------------------------------------------------------------------------------------------------] 100.00% 1.47 GiB p/s
2022/01/24 11:43:50 Upload DCF74FE9C195C627 complete: 246.png
c7h12 commented

实现了rsync...