TISUnion / QuickBackupM

A backup / restore plugin, with multiple backup slots
GNU General Public License v3.0
148 stars 20 forks source link

Reflink(Copy On Write)支持 #39

Closed tksmly closed 1 year ago

tksmly commented 1 year ago

https://github.com/TISUnion/QuickBackupM/issues/38 未经过充分测试,基本功能正常

在btrfs下备份时间由30.1s缩短至2.2s xfs,zfs同理 其他文件系统理论上无影响,未测试

Fallen-Breath commented 1 year ago
tksmly commented 1 year ago

我怀疑我是***但是我没有证据 为什么没有人告诉我这玩意只有linux才有

Fallen-Breath commented 1 year ago

在 review 前,请完成充分的测试,包括但不限于在不同系统平台下,开启/关闭所述功能的拷贝准确性,以及速度对比

tksmly commented 1 year ago

在 review 前,请完成充分的测试,包括但不限于在不同系统平台下,开启/关闭所述功能的拷贝准确性,以及速度对比

拷贝准确性已完成测试,速度对比进行

tksmly commented 1 year ago

为保证准确性删除session.lock后进行压缩对比md5 将windows11iso复制进world目录进行大文件测试 将含有18000+文件的.config目录复制进world目录进行小文件测试

tksmly commented 1 year ago

arch linux+ntfs:37.6s-48.1s arch linux+btrfs:0.6s-2.2s

windows11iso md5相同 zip记录打包时间,就算是一样的文件md5也不同....... 随便拉几个出来都是没问题的

tksmly commented 1 year ago

windows+ntfs:60.9-61.5

tksmly commented 1 year ago

原版qbm: windows+ntfs:60.3-61.7 arch linux+ntfs:43.0-50.7 arch linux+btrfs:15.2-19.4

除了btrfs其他的都是误差范围

Fallen-Breath commented 1 year ago

请在进行完所有的测试后,进行统一的结果汇总展示,而不是把这里当做测试实况播报

tksmly commented 1 year ago
环境 Reflink支持 原版qbm
linux+ntfs 37.6s-48.1s 43.0s-50.7s
linux+btrfs 0.6s-2.2s 15.2s-19.4s
windows+ntfs 60.9s-61.5s 60.3s-61.7s

误差很大,但是除了btrfs其他的都是误差范围

拷贝准确性没有任何问题

Fallen-Breath commented 1 year ago
环境 Reflink支持 原版qbm
linux+ntfs 37.6s-48.1s 43.0s-50.7s
linux+btrfs 0.6s-2.2s 15.2s-19.4s
windows+ntfs 60.9s-61.5s 60.3s-61.7s

误差很大,但是除了btrfs其他的都是误差范围

拷贝准确性没有任何问题

测试方式是什么,包括速度的测试方式,以及准确性的测试方式

测试的环境是什么,包括具体系统版本,硬盘硬件信息

是否有测试多world_names的情况,world_names含单独文件的情况,world_name含文件路径分隔符的各种特殊情况

tksmly commented 1 year ago

应该是没问题了

Fallen-Breath commented 1 year ago

请不遗漏地阅读我提出的所有测试/实现的修改点,并做出完善/回应

tksmly commented 1 year ago

环境 Reflink支持 原版qbm

linux+ntfs 37.6s-48.1s 43.0s-50.7s

linux+btrfs 0.6s-2.2s 15.2s-19.4s

windows+ntfs 60.9s-61.5s 60.3s-61.7s

误差很大,但是除了btrfs其他的都是误差范围 拷贝准确性没有任何问题

测试方式是什么,包括速度的测试方式,以及准确性的测试方式

测试的环境是什么,包括具体系统版本,硬盘硬件信息

是否有测试多world_names的情况,world_names含单独文件的情况,world_name含文件路径分隔符的各种特殊情况

备份三次时间,md5 btrfs和ntfs不是同一块硬盘,只有横向有可比性

只改了复制函数,world_names的判定还是之前的

tksmly commented 1 year ago

https://github.com/TISUnion/QuickBackupM/pull/39#discussion_r1161118450 也许旧的可读性更高

with open(src_path,'rb') as f11, open(dst_path,'wb+') as f21:
    f1 = f11.fileno()
    f2 = f21.fileno()
    size = os.path.getsize(src_path)
        if size > COW_COPY_LIMIT:
            for i in range(0, size, COW_COPY_LIMIT):
                os.copy_file_range(f1, f2, COW_COPY_LIMIT, i) 
        else:
            os.copy_file_range(f1, f2, size)
Fallen-Breath commented 1 year ago

注意 os.copy_file_range 的文档,可以不传递 offset_srcoffset_dst 这两个变量。因此这部分代码可以简化为:

with open(src_file, 'rb') as src, open(dst_file, 'wb') as dst:
    while True:
        if os.copy_file_range(src.fileno(), dst.fileno(), BLOCK_SIZE) <= 0:
            break

同时,正如文档中所述

Additionally, some filesystems could implement extra optimizations, such as the use of reflinks (i.e., two or more inodes that share pointers to the same copy-on-write disk blocks; supported file systems include btrfs and XFS) and server-side copy (in the case of NFS).

os.copy_file_range 并不能保证可以使用 COW 优化。在 Ubuntu20,内核 5.13.0,python 3.8.10,ext4 文件系统 的环境下测试,os.copy_file_rangeshutil.copy 慢了 7%。我建议将 copy_file_range 作为一个可配置的特性开关,并且保持默认关闭。

tksmly commented 1 year ago

作为一个可配置的特性开关,并且保持默认关闭。

那样的话也许应该试试通用的增量备份? 未更改的文件只保留一份最旧的

Fallen-Breath commented 1 year ago

作为一个可配置的特性开关,并且保持默认关闭。

那样的话也许应该试试通用的增量备份? 未更改的文件只保留一份最旧的

这是另一个 feature request,与本 PR 无关

tksmly commented 1 year ago

因此这部分代码可以简化为:

with open(src_file, 'rb') as src, open(dst_file, 'wb') as dst:
    while True:
        if os.copy_file_range(src.fileno(), dst.fileno(), BLOCK_SIZE) <= 0:
            break

也许应该更进一步成这样?

with open(src_file, 'rb') as src, open(dst_file, 'wb') as dst:
while os.copy_file_range(src.fileno(), dst.fileno(), BLOCK_SIZE) :
pass
Fallen-Breath commented 1 year ago

当然可以。https://github.com/TISUnion/QuickBackupM/pull/39#issuecomment-1529003169 的代码仅仅是一个例子,并非必须实现

不过,修改后的实现进行了从 intbool 的隐式类型转换,对我个人而言我是不推崇这种做法的。此外这里还作出了 copy_file_range 返回值不会小于 0 的期望(虽然问题应该不大)。具体究竟怎么实现,你自己决定

Fallen-Breath commented 1 year ago

基本没什么问题了,然后就是得整理下代码格式,包括运算符前后的空格、logger.warning 里混用 str.format+、无用的空行、行内注释的 2 空格等等,参考 pep8

最后就是给 readme 加上新配置项的文档了

Fallen-Breath commented 1 year ago

https://github.com/TISUnion/QuickBackupM/pull/39#discussion_r1186602665 这里提的 COW_COPY_BUFFER_SIZE 的取值测试做一下,然后就 ok 了。之后合并了我再整理下细节吧

tksmly commented 1 year ago

#39 (comment) 这里提的 COW_COPY_BUFFER_SIZE 的取值测试做一下,然后就 ok 了。之后合并了我再整理下细节吧

更大的值会带来提升,但边际效应明显,精准测试不好做,因为提升还没有误差大, 现在的取值比较理想,毕竟这个不是真正的buffer,只是逻辑上的

Fallen-Breath commented 1 year ago

#39 (comment) 这里提的 COW_COPY_BUFFER_SIZE 的取值测试做一下,然后就 ok 了。之后合并了我再整理下细节吧

更大的值会带来提升,但边际效应明显,精准测试不好做,因为提升还没有误差大, 现在的取值比较理想,毕竟这个不是真正的buffer,只是逻辑上的

对于 https://github.com/TISUnion/QuickBackupM/pull/39#discussion_r1186602665 中建议的测试,使用的 buffer 取值是更小的值,而非更大的值。毕竟这只是个 buffer,调整成 buffer 常见的大小可能会有不一样的性能表现

tksmly commented 1 year ago

毕竟这只是个 buffer,调整成 buffer 常见的大小可能会有不一样的性能表现

这不是buffer,这是减少python层循环次数的buffer-like 因为c循环不会构成瓶颈,但py循环会


使用大量杂乱文件与其压缩包进行测试,

4k约为5s 16k约为2s-3s 1g约为1s-2s

边际效应非常明显,但是增加这个值没有任何坏处,在不出错的情况下应当尽可能提升这个值

Fallen-Breath commented 1 year ago

这不是buffer,这是减少python层循环次数的buffer-like

在 cpython 的实现下,这个参数是会直接传递给系统调用的,因此这可能会对实际性能产生影响。虽然正如 https://github.com/TISUnion/QuickBackupM/pull/39#discussion_r1155882544 所说,glibc 的实现是没问题的

因为c循环不会构成瓶颈,但py循环会

我不认为 1E3 以下数量级的 python 循环会产生任何瓶颈,除非有相关的性能分析证明

使用大量杂乱文件与其压缩包进行测试

能详细说明下吗,是分别测试,还是同时测试。没啥没问题的话,这样就 ok 了

tksmly commented 1 year ago

能详细说明下吗,是分别测试,还是同时测试。

同时

我不认为 1E3 以下数量级的 python 循环会产生任何瓶颈

我的测试文件大概1E4, 1s确实不算瓶颈,但是总共也就几s欸

Fallen-Breath commented 1 year ago

“我不认为 1E3 以下数量级”,这里的 1E3 指的是,使用 https://github.com/TISUnion/QuickBackupM/pull/39#discussion_r1186602665 中建议取值最小的 10MiB 的情况,循环拷贝可能较大文件 10GiB,需要 10GiB / 10MiB = 约 1E3 次 python 循环调用 os.copy_file_range。不知你说的 1E4 是什么情况

tksmly commented 1 year ago

“我不认为 1E3 以下数量级”,这里的 1E3 指的是,使用 #39 (comment) 中建议取值最小的 10MiB 的情况,循环拷贝可能较大文件 10GiB,需要 10GiB / 10MiB = 约 1E3 次 python 循环调用 os.copy_file_range。不知你说的 1E4 是什么情况

文件数量

不要低估日用linux平台的config目录

Fallen-Breath commented 1 year ago

“我不认为 1E3 以下数量级”,这里的 1E3 指的是,使用 #39 (comment) 中建议取值最小的 10MiB 的情况,循环拷贝可能较大文件 10GiB,需要 10GiB / 10MiB = 约 1E3 次 python 循环调用 os.copy_file_range。不知你说的 1E4 是什么情况

文件数量

不要低估日用linux平台的config目录

这跟你在 https://github.com/TISUnion/QuickBackupM/pull/39#issuecomment-1541293869 说的是不是不太匹配?

“这不是buffer,这是减少python层循环次数的buffer-like。因为c循环不会构成瓶颈,但py循环会”

在谈论 buffer 作为上下文的时,循环次数应该指的是循环调用 os.copy_file_range 的次数。而“文件数量”,指的是调用 _cpcow 的次数,这与 os.copy_file_range 的循环次数导致的性能影响不太相关啊

Fallen-Breath commented 1 year ago

对于 https://github.com/TISUnion/QuickBackupM/pull/39#issuecomment-1541293869 中的 COW_COPY_BUFFER_SIZE 测试,正确的测试方式应该是使用不同的 buffer size 值,来拷贝文件大小不同的文件多次,文件大小应当覆盖常见的量级

对于测试结果,我已经反复多次提出该怎么客观严谨表述一份测试结果。https://github.com/TISUnion/QuickBackupM/pull/39#issuecomment-1541293869 中对结果的描述是非常含糊不清缺少信息的。


算了,估计你也不会好好测,就不浪费时间了,buffer 大小这部分影响也不大,就这样吧

tksmly commented 1 year ago

_cpcow 的次数,这与 os.copy_file_range 的循环次数导致的性能影响不太相关啊

不仅仅是大量小文件,还有整个打包的zip