中文版 | english
hsynz 是一个用使用同步算法来进行增量更新的库,类似于 zsync。
通过http(s)实现rsync;在客户端实现同步算法,服务器端只需要提供http(s)的CDN。支持zstd、libdeflate和zlib压缩,支持大文件和目录(文件夹),支持多线程。
适用的场景:旧版本数量非常多 或者 无法得到旧版本(没有保存或被修改等) 从而无法提前计算出全部的增量补丁,这时推荐使用hsynz同步分发技术。
服务端使用hsync_make对最新版本的数据进行一次处理,将新版本数据按块生成摘要信息文件(hsyni),同时也可以选择对新版本数据分块进行压缩得到发布文件(hsynz),如果不压缩新版本原文件就是hsynz等价文件。
客户端先从服务端或其他用户分享处下载hsyni文件,根据自己的旧版本计算出需要下载的更新块,并根据hsyni中的信息得知这些块在hsynz中的位置,选择一种通讯方式从服务端的hsynz文件中按需下载,下载好的块和本地已有数据合并得到最新版本的数据。
hsync_demo提供了一个测试客户端demo,用于本地文件测试。
hsync_http提供了一个支持http(s)的下载客户端demo,支持从提供http(s)文件下载服务的服务端(比如支持HTTP/1.1的多range请求的CDN服务器)进行同步更新。
提示:你也可以自定义其他通讯方式用于同步。
特性和 zsync 对比
- 除了支持源和目标为文件,还为文件夹(目录)提供了支持。
- 除了支持zlib压缩发布包;还支持libdeflate和zstd压缩,提供更好的压缩率,即下载的补丁包更小。
- 服务端make时提供了多线程并行加速的支持。
- 对客户端的diff速度进行了优化,并且提供了多线程并行加速的支持。
从 release 下载 : 分别运行在 Windows、Linux、MacOS操作系统的命令行程序; .so 库用以支持安卓系统进行同步打补丁。
( 编译出这些发布文件的项目路径在 hsynz/builds
)
$ cd <dir>
$ git clone --recursive https://github.com/sisong/hsynz.git
$ cd hsynz
$ make
$ cd <dir>
$ git clone --recursive https://github.com/sisong/hsynz.git
用 Visual Studio
打开 hsynz/builds/vc/hsynz.sln
编译
- 先安装好 Android NDK
$ cd <dir>/hsynz/builds/android_ndk_jni_mk
$ build_libs_static.sh
(或者在 windows 系统上执行$ build_libs_static.bat
, 就可以得到 *.so 文件)- 安卓项目添加
com/github/sisong/hsynz.java
(路径在hsynz/builds/android_ndk_jni_mk/java/
) 和 .so 库文件, java代码中就可以调用libhsynz.so中的同步补丁函数了。
hsync_make: [options] newDataPath out_hsyni_file [out_hsynz_file]
newDataPath可以是文件或目录, 如果newDataPath是文件并且不使用压缩参数 -c-... , 那out_hsynz_file
参数可以为空.(因为这时out_hsynz_file和newDataPath文件完全一致,不需要重新再复制一个)
选项:
-s-matchBlockSize
匹配块大小matchBlockSize>=128, 默认为-s-2k, 推荐设置值 1024,4k,... (一般文件越大设置值建议越大)
-b-safeBit
设置允许patch时因hash冲突而失败的概率为: 1/2^safeBit;
安全比特数safeBit>=14, 默认为 -b-24, 推荐 20,32...
(safeBit=24,也就是对任意一个旧版本大概有1/2^24的概率patch一定会失败;而值越大out_hsyni_file信息文件越大)
-p-parallelThreadNumber
设置线程数parallelThreadNumber>1时,开启多线程并行模式;
默认为4;需要占用较多的内存。
-c-compressType[-compressLevel]
设置out_hsynz_file输出文件使用的压缩算法和压缩级别等, 默认不压缩;
所有的压缩算法都支持多线程并行压缩;
支持的压缩算法、压缩级别和字典大小等:
-c-zlib[-{1..9}[-dictBits]] 默认级别 9
压缩字典比特数dictBits可以为9到15, 默认为15。
-c-gzip[-{1..9}[-dictBits]] 默认级别 9
压缩字典比特数dictBits可以为9到15, 默认为15。
使用zlib算法来压缩, out_hsynz_file输出文件将是一个标准的.gz格式文件。
(会比 -c-zlib 生成的文件稍大一点)
-c-ldef[-{1..12}] 默认级别 12
压缩字典比特数dictBits总是设置为15。
使用libdeflate算法来压缩, 兼容zlib的deflate编码。
-c-lgzip[-{1..12}] 默认级别 12
压缩字典比特数dictBits总是设置为15。
使用libdeflate算法来压缩, out_hsynz_file输出文件将是一个标准的.gz格式文件。
-c-zstd[-{10..22}[-dictBits]] 默认级别 21
压缩字典比特数dictBits 可以为15到30, 默认为24。
-C-checksumType
设置块数据的强校验算法, 默认为-C-xxh128;
支持的校验选项:
-C-xxh128
-C-md5
-C-sha512
-C-sha256
-C-crc32
警告: crc32不够强和安全!
-n-maxOpenFileNumber
当newDataPath为文件夹时,设置最大允许同时打开的文件数;
maxOpenFileNumber>=8, 默认为48; 合适的限制值可能不同系统下不同。
-g#ignorePath[#ignorePath#...]
当newDataPath为文件夹时,设置忽略路径(路径可能是文件或文件夹); 忽略路径列表的格式如下:
#.DS_Store#desktop.ini#*thumbs*.db#.git*#.svn/#cache_*/00*11/*.tmp
# 意味着路径名称之间的间隔; (如果名称中有“#”号, 需要改写为“#:” )
* 意味着匹配名称中的任意一段字符; (如果名称中有“*”号, 需要改写为“*:” )
/ 如果该符号放在名称末尾,意味着必须匹配文件夹;
-f 强制文件写覆盖, 忽略输出的路径是否已经存在;
默认不执行覆盖, 如果输出路径已经存在, 直接返回错误;
如果设置了-f,但路径已经存在并且是一个文件夹, 那么会始终返回错误。
--patch
切换命令行到hsync_demo模式; 可以支持hsync_demo命令行的相关参数和功能。
-v 输出程序版本信息。
-h 或 -?
输出命令行帮助信息 (该说明)。
下载文件 : [options] -dl#hsyni_file_url hsyni_file
创建本地补丁: [options] oldPath hsyni_file hsynz_file_url -diff#diffFile
本地打补丁 : [options] oldPath hsyni_file -patch#diffFile outNewPath
查询同步信息: [options] oldPath hsyni_file [-diffi#cacheTempFile]
同步打补丁 : [options] oldPath [-dl#hsyni_file_url] hsyni_file hsynz_file_url outNewPath [-diffi#cacheTempFile]
oldPath可以是文件或文件夹;oldPath可以为空, 输入参数为 ""
选项:
-dl#hsyni_file_url
在同步打补丁开始前,将hsyni_file_url对应的文件下载为本地文件hsyni_file;
-diff#outDiffFile
开始打补丁前,创建oldPath到hsyni_file描述的新版间的diffFile补丁文件,本地没有的块按需从hsynz_file_url下载;
-patch#diffFile
对oldPath应用diffFile补丁文件后得到outNewPath;
-diffi#cacheTempFile
获得的同步信息保存到一个临时缓存文件cacheTempFile,同步打补丁的时候,就可以跳过同步信息的耗时计算过程;
-cdl
开启断点续传;默认关闭;
-r-stepRangeNumber
默认 -r-32, 推荐 16,20,...
从.hsynz下载时,限制在单次请求步骤中的最大区域(range)数;
如果http(s)服务器不支持多区域(muti-ranges)请求, 必须设置为 -r-1
-p-parallelThreadNumber
设置线程数parallelThreadNumber>1时,开启多线程并行模式;
默认为4;
注意: 当前下载数据时使用的是单线程。
-n-maxOpenFileNumber
当路径为文件夹时,设置最大允许同时打开的文件数;
maxOpenFileNumber>=8, 默认为24; 合适的限制值可能不同系统下不同。
-g#ignorePath[#ignorePath#...]
当oldPath为文件夹时,设置忽略路径(路径可能是文件或文件夹); 忽略路径列表的格式如下:
#.DS_Store#desktop.ini#*thumbs*.db#.git*#.svn/#cache_*/00*11/*.tmp
# 意味着路径名称之间的间隔; (如果名称中有“#”号, 需要改写为“#:” )
* 意味着匹配名称中的任意一段字符; (如果名称中有“*”号, 需要改写为“*:” )
/ 如果该符号放在名称末尾,意味着必须匹配文件夹;
-f 强制文件写覆盖, 忽略输出的路径是否已经存在;
默认不执行覆盖, 如果输出路径已经存在, 直接返回错误;
如果设置了-f,但outNewPath已经存在并且是一个文件:
如果patch输出一个文件, 那么会执行写覆盖;
如果patch输出一个文件夹, 那么会始终返回错误。
如果设置了-f,但outNewPath已经存在并且是一个文件夹:
如果patch输出一个文件, 那么会始终返回错误;
如果patch输出一个文件夹, 那么会执行写覆盖, 但不会删除文件夹中已经存在的无关文件。
-v 输出程序版本信息。
-h 或 -?
输出命令行帮助信息 (该说明)。
该程序功能用于本地同步测试,用本地文件代替实际中的URL远程文件,详见hsync_http命令行。
hsynz 和 zsync 性能对比:
测试用例(从 OneDrive 下载):
新版本文件 <-- 旧版本 | 新版本大小 | 旧版本大小 | |
---|---|---|---|
1 | 7-Zip_22.01.win.tar <-- 7-Zip_21.07.win.tar | 5908992 | 5748224 |
2 | Chrome_107.0.5304.122-x64-Stable.win.tar <-- 106.0.5249.119 | 278658560 | 273026560 |
3 | cpu-z_2.03-en.win.tar <-- cpu-z_2.02-en.win.tar | 8718336 | 8643072 |
4 | curl_7.86.0.src.tar <-- curl_7.85.0.src.tar | 26275840 | 26030080 |
5 | douyin_1.5.1.mac.tar <-- douyin_1.4.2.mac.tar | 407940608 | 407642624 |
6 | Emacs_28.2-universal.mac.tar <-- Emacs_27.2-3-universal.mac.tar | 196380160 | 257496064 |
7 | FFmpeg-n_5.1.2.src.tar <-- FFmpeg-n_4.4.3.src.tar | 80527360 | 76154880 |
8 | gcc_12.2.0.src.tar <-- gcc_11.3.0.src.tar | 865884160 | 824309760 |
9 | git_2.33.0-intel-universal-mavericks.mac.tar <-- 2.31.0 | 73302528 | 70990848 |
10 | go_1.19.3.linux-amd64.tar <-- go_1.19.2.linux-amd64.tar | 468835840 | 468796416 |
11 | jdk_x64_mac_openj9_16.0.1_9_openj9-0.26.0.tar <-- 9_15.0.2_7-0.24.0 | 363765760 | 327188480 |
12 | jre_1.8.0_351-linux-x64.tar <-- jre_1.8.0_311-linux-x64.tar | 267796480 | 257996800 |
13 | linux_5.19.9.src.tar <-- linux_5.15.80.src.tar | 1269637120 | 1138933760 |
14 | Minecraft_175.win.tar <-- Minecraft_172.win.tar | 166643200 | 180084736 |
15 | OpenOffice_4.1.13.mac.tar <-- OpenOffice_4.1.10.mac.tar | 408364032 | 408336896 |
16 | postgresql_15.1.src.tar <-- postgresql_14.6.src.tar | 151787520 | 147660800 |
17 | QQ_9.6.9.win.tar <-- QQ_9.6.8.win.tar | 465045504 | 464837120 |
18 | tensorflow_2.10.1.src.tar <-- tensorflow_2.8.4.src.tar | 275548160 | 259246080 |
19 | VSCode-win32-x64_1.73.1.tar <-- VSCode-win32-x64_1.69.2.tar | 364025856 | 340256768 |
20 | WeChat_3.8.0.41.win.tar <-- WeChat_3.8.0.33.win.tar | 505876992 | 505018368 |
测试PC: Windows11, CPU R9-7945HX, SSD PCIe4.0x4 4T, DDR5 5200MHz 32Gx2
参与测试的程序版本: hsynz 1.1.1, zsync 0.6.2 (更多程序的对比测试结果见 HDiffPatch)
程序测试参数:
zsync 运行 make 参数 zsyncmake -b 2048 -o {out_newi} {new}
,
客户端同步 diff&patch 时参数 zsync -i {old} -o {out_new} {newi}
(所有文件都在本地)
zsync -z 运行 make 参数 zsyncmake -b 2048 -z -u {new.gz} -o {out_newi} {new}
hsynz 运行 make 参数 hsync_make -s-2k {new} {out_newi} [{-c-?} {out_newz}]
,
客户端同步 diff&patch 时参数 hsync_demo {old} {newi} {newz} {out_new}
(所有文件都在本地)
hsynz p1 运行 make 时没有压缩器,也没有压缩文件out_newz输出, 添加了参数 -p-1
hsynz p8 运行 make 时没有压缩器,也没有压缩文件out_newz输出, 添加了参数 -p-8
hsynz p1 -zlib 运行 make 时添加 -p-1 -c-zlib-9
(运行 hsync_demo
时添加 -p-1
)
hsynz p8 -zlib 运行 make 时添加 -p-8 -c-zlib-9
(运行 hsync_demo
时添加 -p-8
)
hsynz p1 -gzip 运行 make 时添加 -p-1 -c-gzip-9
(运行 hsync_demo
时添加 -p-1
)
hsynz p8 -gzip 运行 make 时添加 -p-8 -c-gzip-9
(运行 hsync_demo
时添加 -p-8
)
hsynz p1 -ldef 运行 make 时添加 -p-1 -c-ldef-12
(运行 hsync_demo
时添加 -p-1
)
hsynz p8 -ldef 运行 make 时添加 -p-8 -c-ldef-12
(运行 hsync_demo
时添加 -p-8
)
hsynz p1 -lgzip 运行 make 时添加 -p-1 -c-lgzip-12
(运行 hsync_demo
时添加 -p-1
)
hsynz p8 -lgzip 运行 make 时添加 -p-8 -c-lgzip-12
(运行 hsync_demo
时添加 -p-8
)
hsynz p1 -zstd 运行 make 时添加 -p-1 -c-zstd-21-24
(运行 hsync_demo
时添加 -p-1
)
hsynz p8 -zstd 运行 make 时添加 -p-8 -c-zstd-21-24
(运行 hsync_demo
时添加 -p-8
)
测试平均结果:
程序 | 压缩率 | make内存 | 速度 | sync内存 | 最大内存 | 速度 |
---|---|---|---|---|---|---|
zsync | 52.94% | 1M | 353.9MB/s | 7M | 23M | 34MB/s |
zsync -z | 20.67% | 1M | 14.8MB/s | 12M | 37M | 28MB/s |
hsynz p1 | 51.05% | 5M | 2039.5MB/s | 5M | 19M | 307MB/s |
hsynz p8 | 51.05% | 21M | 4311.9MB/s | 12M | 27M | 533MB/s |
hsynz p1 zlib | 20.05% | 6M | 17.3MB/s | 6M | 22M | 273MB/s |
hsynz p8 zlib | 20.05% | 30M | 115.1MB/s | 13M | 29M | 435MB/s |
hsynz p1 gzip | 20.12% | 6M | 17.3MB/s | 6M | 22M | 268MB/s |
hsynz p8 gzip | 20.12% | 30M | 115.0MB/s | 13M | 29M | 427MB/s |
hsynz p1 ldef | 19.57% | 15M | 7.8MB/s | 6M | 22M | 272MB/s |
hsynz p8 ldef | 19.57% | 96M | 57.0MB/s | 13M | 29M | 431MB/s |
hsynz p1 lgzip | 19.64% | 15M | 7.9MB/s | 6M | 22M | 267MB/s |
hsynz p8 lgzip | 19.64% | 96M | 56.9MB/s | 13M | 29M | 419MB/s |
hsynz p1 zstd | 14.96% | 532M | 1.9MB/s | 24M | 34M | 264MB/s |
hsynz p8 zstd | 14.95% | 3349M | 10.1MB/s | 24M | 34M | 410MB/s |
case list:
调整测试程序:
zsync ... make 参数 -b 2048
修改为 -b 1024
hsynz ... make 参数 -s-2k
修改为 -s-1k
测试平均结果:
程序 | 压缩率 | make内存 | 速度 | sync内存 | 最大内存 | 速度 |
---|---|---|---|---|---|---|
zsync | 62.80% | 1M | 329.8MB/s | 6M | 12M | 76MB/s |
zsync -z | 59.56% | 1M | 19.8MB/s | 8M | 19M | 56MB/s |
hsynz p1 | 62.43% | 4M | 1533.5MB/s | 4M | 10M | 236MB/s |
hsynz p8 | 62.43% | 18M | 2336.4MB/s | 12M | 18M | 394MB/s |
hsynz p1 zlib | 58.67% | 5M | 22.7MB/s | 4M | 11M | 243MB/s |
hsynz p8 zlib | 58.67% | 29M | 138.6MB/s | 12M | 19M | 410MB/s |
hsynz p1 gzip | 58.95% | 5M | 22.6MB/s | 4M | 11M | 242MB/s |
hsynz p8 gzip | 58.95% | 29M | 138.9MB/s | 12M | 19M | 407MB/s |
hsynz p1 ldef | 58.61% | 14M | 23.7MB/s | 4M | 11M | 242MB/s |
hsynz p8 ldef | 58.61% | 96M | 149.1MB/s | 12M | 19M | 413MB/s |
hsynz p1 lgzip | 58.90% | 14M | 23.6MB/s | 4M | 11M | 240MB/s |
hsynz p8 lgzip | 58.90% | 96M | 149.1MB/s | 12M | 19M | 405MB/s |
hsynz p1 zstd | 57.74% | 534M | 2.7MB/s | 24M | 28M | 234MB/s |
hsynz p8 zstd | 57.74% | 3434M | 13.4MB/s | 24M | 28M | 390MB/s |