问题说明

项目地址:musnows/encrypt2bdy

之前自己瞎写了一个上传文件到百度云的python程序,提供了docker并部署在了我自己的nas上,但是我限制容器可用内存大小为1GB后,总是会遇到docker因为内存爆满直接被系统kill了的情况。

现在总算有时间看看到底是啥问题了,其实我已经能想到了,上传文件的部分已经是按分片上传的,理论上不是那个地方的问题,另外一个打开文件的地方只有一处,就是计算文件整体md5的操作。

因为当时没想明白问题在哪里,我还在项目的README里面写了一个不建议用于备份大文件,因为内存会撑爆的提示(

1
2
3
4
5
6
7
## 已知错误

### 1.docker退出码137

内存不足时,系统将对应docker容器终止。出现此问题,请确认您要备份的文件中不会出现大于您系统内存或docker容器内存限制的文件。

正如开头所说,本项目适合于备份照片、图片、文档等小文件,并不建议用于备份录像、电影等资源。

原有代码读取md5的方式

在程序中,我计算文件整体md5的操作是这样写的

1
2
3
4
5
6
7
# 打开文件
with open(file_path, 'rb') as f:
file_bytes = f.read()
# 1.计算文件md5,判断文件是否存在于数据中
file_name = os.path.basename(file_path) # 文件名
file_md5_str = hashlib.md5(file_bytes).hexdigest()
_log.debug(f"{file_path} | {file_md5_str}")

问题其实很明朗,就是这里的f.read()操作直接将整个文件加载到内存里面了!备份的文件稍微大一点,指定要把内存整爆的!

分片读取md5

这部分代码应该替换为如下形式,分片读取文件,并将读取的md5给update到hashlib.md5()对象中

1
2
3
4
5
6
7
8
def file_md5(file_path: str):
"""给定一个文件路径,分片加载文件,计算文件的md5"""
chunk_size = 4096 # 根据需要调整单块的大小
with open(file_path, 'rb') as f:
file_md5 = hashlib.md5()
while chunk := f.read(chunk_size):
file_md5.update(chunk)
return file_md5.hexdigest()

经过测试,这种办法计算出来的md5和直接f.read()全部计算出的md5完全一致

1
2
3
╰─ python3.10 test.py                 
ca60e24bf4dde156a381c8b9d268faf5
ca60e24bf4dde156a381c8b9d268faf5

内存占用监控线程

用下面的代码弄个内存占用的监控线程,通过psutil库实时打印内存占用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import psutil
import os
import threading
import time


def monitor_memory_usage():
process = psutil.Process(os.getpid())
while True:
memory_info = process.memory_info()
print(f"Memory used: {memory_info.rss / (1024 * 1024):.2f} MB")
time.sleep(1) # 每秒更新一次内存信息


# 启动一个线程来监视内存使用情况
memory_monitor_thread = threading.Thread(target=monitor_memory_usage)
memory_monitor_thread.start()

# 主线程继续执行其他任务

# 等待监视线程结束(如果需要)
memory_monitor_thread.join()

内存占用测试

将项目中上传到百度云的部分注释掉,休眠10秒替代上传操作,模拟原有代码整体打开一个文件,又分片打开文件上传到百度云的流程。

用两个450MB左右的视频做测试。程序原有思路是遍历需要备份目录中的所有文件,分片上传到百度云。计算整个文件的MD5的操作其实是用来本地入库标定文件是否有修改、是否已经上传的。

不过后续加密文件的操作也是无脑f.read(),这部分也需要修改。

image.png

日志输出如下,可以看到,开始处理test目录之后,程序直接把视频完整加载到了内存里面,占用内存的大小和视频文件大小基本一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
╰─ python3.10 main.py
[23-12-17 20:01:22] INFO:confLoad.py:<module>:68 | [config] loaded config from './config/config.yml'
[23-12-17 20:01:22] INFO:confLoad.py:<module>:89 | [config] loaded config success
[23-12-17 20:01:22] INFO:querySql.py:<module>:72 | [sqlite3] create all tables
[23-12-17 20:01:23] INFO:main.py:<module>:294 | [start] start at 23-12-17 20:01:23
[23-12-17 20:01:23] INFO:encrypt.py:__init__:24 | load key file from './config/encrypt.key'
Memory used: 39.18 MB
[23-12-17 20:01:23] INFO:main.py:upload_task:132 | 上传任务开始:23-12-17 20:01:23
[23-12-17 20:01:23] INFO:main.py:upload_task:139 | 开始处理路径 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test' | 文件数量 2
[23-12-17 20:01:23] INFO:main.py:upload_task:144 | [0] 开始处理 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《ILLSHOWYOU》KDA阿狸.mp4'
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
Memory used: 483.52 MB
[23-12-17 20:01:33] INFO:main.py:upload_task:237 | [1] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《ILLSHOWYOU》KDA阿狸.mp4' 文件哈希:7d5735eba55a638a1290ab36e00530ca
[23-12-17 20:01:33] INFO:main.py:upload_task:144 | [1] 开始处理 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《MORE》KDA.mp4'
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
Memory used: 517.39 MB
[23-12-17 20:01:44] INFO:main.py:upload_task:237 | [2] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《MORE》KDA.mp4' 文件哈希:b7b0cd46e3ac7681a3644d9761ad3e71
[23-12-17 20:01:44] INFO:main.py:upload_task:282 | 本次上传完毕,上传:2,跳过:0,错误:0 | 总计:2
[23-12-17 20:01:44] INFO:main.py:upload_task:283 | 本次上传完毕,平均上传速度:43.143mb/s | 总耗时:21.16s
[23-12-17 20:01:44] INFO:main.py:upload_task:286 | 本次上传完毕,下次处理:2023-12-17 21:00:00

带上加密之后更加离谱,只是第一个文件就直接把内存占用干到了3.2GB,处理第二个文件的时候,也是直接干到了2.4GB,这种程度的内存消耗谁顶得住?更何况百度云API最大支持10GB的文件上传,如果要加载一个10GB的文件还得了啊?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
╰─ python3.10 main.py
[23-12-17 19:43:56] INFO:confLoad.py:<module>:68 | [config] loaded config from './config/config.yml'
[23-12-17 19:43:56] INFO:confLoad.py:<module>:89 | [config] loaded config success
[23-12-17 19:43:56] INFO:querySql.py:<module>:72 | [sqlite3] create all tables
[23-12-17 19:43:56] INFO:main.py:<module>:291 | [start] start at 23-12-17 19:43:56
Memory used: 39.31 MB
[23-12-17 19:43:56] INFO:encrypt.py:__init__:24 | load key file from './config/encrypt.key'
[23-12-17 19:43:56] INFO:main.py:upload_task:132 | 上传任务开始:23-12-17 19:43:56
[23-12-17 19:43:56] INFO:main.py:upload_task:139 | 开始处理路径 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test' | 文件数量 2
Memory used: 923.04 MB
Memory used: 3267.48 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
Memory used: 483.71 MB
[23-12-17 19:44:08] INFO:main.py:upload_task:234 | [1] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《ILLSHOWYOU》KDA阿狸.mp4' 文件哈希:7d5735eba55a638a1290ab36e00530ca
Memory used: 990.96 MB
Memory used: 2410.97 MB
Memory used: 1622.17 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
Memory used: 517.57 MB
[23-12-17 19:44:22] INFO:main.py:upload_task:234 | [2] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《MORE》KDA.mp4' 文件哈希:b7b0cd46e3ac7681a3644d9761ad3e71
[23-12-17 19:44:22] INFO:main.py:upload_task:279 | 本次上传完毕,上传:2,跳过:0,错误:0 | 总计:2
[23-12-17 19:44:22] INFO:main.py:upload_task:280 | 本次上传完毕,平均上传速度:35.371mb/s | 总耗时:25.81s
[23-12-17 19:44:22] INFO:main.py:upload_task:283 | 本次上传完毕,下次处理:2023-12-17 21:00:00

先将md5计算的函数给修改了,改成分片计算。可以看到,效果显著!内存占用和程序刚开始运行的时候差距只有5MB,这才是正常的内存占用!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
╰─ python3.10 main.py
[23-12-17 20:03:20] INFO:confLoad.py:<module>:68 | [config] loaded config from './config/config.yml'
[23-12-17 20:03:20] INFO:confLoad.py:<module>:89 | [config] loaded config success
[23-12-17 20:03:20] INFO:querySql.py:<module>:72 | [sqlite3] create all tables
[23-12-17 20:03:20] INFO:main.py:<module>:294 | [start] start at 23-12-17 20:03:20
Memory used: 39.26 MB
[23-12-17 20:03:20] INFO:encrypt.py:__init__:24 | load key file from './config/encrypt.key'
[23-12-17 20:03:20] INFO:main.py:upload_task:132 | 上传任务开始:23-12-17 20:03:20
[23-12-17 20:03:20] INFO:main.py:upload_task:139 | 开始处理路径 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test' | 文件数量 2
[23-12-17 20:03:20] INFO:main.py:upload_task:144 | [0] 开始处理 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《ILLSHOWYOU》KDA阿狸.mp4'
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
[23-12-17 20:03:32] INFO:main.py:upload_task:237 | [1] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《ILLSHOWYOU》KDA阿狸.mp4' 文件哈希:7d5735eba55a638a1290ab36e00530ca
[23-12-17 20:03:32] INFO:main.py:upload_task:144 | [1] 开始处理 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《MORE》KDA.mp4'
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
Memory used: 44.08 MB
[23-12-17 20:03:44] INFO:main.py:upload_task:237 | [2] 成功上传 '/home/mu/code-wsl/py-wsl/encrypt2bdy/test/【超丝滑60帧】4K精装字幕版《MORE》KDA.mp4' 文件哈希:b7b0cd46e3ac7681a3644d9761ad3e71
[23-12-17 20:03:44] INFO:main.py:upload_task:282 | 本次上传完毕,上传:2,跳过:0,错误:0 | 总计:2
[23-12-17 20:03:44] INFO:main.py:upload_task:283 | 本次上传完毕,平均上传速度:38.689mb/s | 总耗时:23.60s
[23-12-17 20:03:44] INFO:main.py:upload_task:286 | 本次上传完毕,下次处理:2023-12-17 21:00:00

The end

关于分片计算md5的介绍就这么多,我这个程序里面文件加密的部分也需要修改,不过那就不是本文的范畴了~