为什么rsync不对网络上的单个文件使用增量传输?


15

我已经看过这个问题这个问题,但是它们似乎并没有解决我所看到的症状。

我有一个试图通过蜂窝网络传输的大日志文件(大约600 MB)。因为它是一个日志文件,所以只是附加到日志文件中(尽管它实际上是在SQLite数据库中仅执行INSERT操作,因此它不是那么简单,但是最后一个4k页除外(或者可能是一个很少)文件每次都是相同的,重要的是只有更改(以及需要传输的校验和)才真正被发送,因为数据连接是按计量的。

但是,当我在未测量的连接(例如免费wifi热点)上执行测试时,没有观察到或报告加速或减少的数据传输。通过慢速的WiFi连接,我看到的速度约为1MB / s或更低,报告传输将花费近20分钟。通过快速的WiFi连接,我看到一个统一的更快的速度,但是没有加速报告,并且第二次尝试传输(由于两个文件相同,现在应该更快)现在显示出任何不同。

我正在使用的(经过清理以删除敏感信息)命令是:

rsync 'ssh -p 9999' --progress LogFile michael@my.host.zzz:/home/michael/logs/LogFile

我最终得到的输出如下所示:

LogFile
    640,856,064 100%   21.25MB/s   0:00:28 (xfr$1, to-chk=0/1)

没有提及任何形式的加速。

我怀疑问题可能是以下之一:

  • 我缺少一些命令行选项。但是,重新阅读手册页似乎表明默认情况下启用了增量传输:我只看到用于禁用它们的选项。
  • 由于服务器位于仅允许ssh的防火墙后面,因此我正在ssh上使用rsync(甚至在非标准端口上)。不过,我还没有看到任何明确的说法,即如果rsync守护进程未运行,则增量传输将不起作用。我尝试使用“ ::”符号代替“:”,但是手册页中关于“模块”的含义不是很清楚,并且我的命令由于指定了无效的模块而被拒绝。

我排除了以下情况:

  • 未在本地网络上执行增量传输。排除在外是因为我正在尝试通过Internet执行传输
  • 由于校验和计算导致的开销。我已经在快速和慢速Wifi连接上都看到了这种行为,并且传输速率似乎不受计算限制。

1
but with the exception of the last 4k page (or maybe a few) the file is identical each time. 您确实通过验证了cmp吗?还是更好,xdelta或者什么?如果您真的想最小化传输大小,请在本地保留新旧版本,这样就可以在本地计算最小的二进制差异(使用rsync以外的其他东西),而不必通过计量连接发送校验和就可以发送。如derobert建议的那样,在数据库记录级别而不是二进制文件级别执行此操作可能会更好。
彼得·科德斯

1
另外,您可能已经使用过rsync --stats,并且还-v -v可以获得更详细的统计信息。Rsync会告诉您有多少匹配数据与不匹配数据。
彼得·科德斯

Answers:


27

摘要

数据库倾向于保留大量的元数据,组织数据等。插入不太可能是简单的追加,就像文本文件一样。测试SQLite可以显示它在WAL和非WAL模式下的行为。这导致rsync必须同步比您期望的更多的数据。您可以通过使用较低的开销来减少此开销--block-size(以更多开销计算和传输校验和为代价)。

更好的方法可能是将新记录转储为SQL转储,对其进行压缩并进行传输。另外,似乎有几种SQLite复制解决方案,您可以使用其中一种。

roaima建议您至少可以进行完整的SQL转储,使用进行压缩gzip --rsyncable,然后rsync。我想值得进行一次测试,看看这是否足够小。

细节

您正在尝试的应该起作用。我个人会添加--partial到您的rsync选项中,以防万一某种方式将正在增长的文件检测为部分传输。您还可以使用获得更好的转移统计信息--stats

要检查的第二件事是SQLite是否真的只触及了几页-老实说,如果它在整个文件中都写页面,我不会感到惊讶。一种快速的检查方法是cmp -l在两个版本上使用-查看除最后几个页面以外是否对页面进行了更改。记住,rsync“页面” /块的思想不同于SQLite的思想。您可以通过更改rsync的--block-size。减少它可能会有所帮助。

编辑:我用SQLite进行了快速测试。即使有32,000页,在每页上添加了一些日志条目。详细信息如下。

编辑2:在WAL模式下,它看起来似乎更好,尽管您仍然要承担大量的开销(可能来自检查点)。

编辑3:每次传输添加的数据越多越好-我想它可能会一遍又一遍地乱涂某些块。因此,无论是写入一次还是一百次,您都在传输同一组块。

顺便说一句:为了最大程度地减少传输,您可能比rsync更好。例如,自上次传输以来xz --best(甚至gzip)以来,新记录的SQL转储可能会小很多。

快速SQLite测试

架构:

CREATE TABLE log (id integer primary key not null, ts integer not null, app text not null, message text not null);
CREATE INDEX log_ts_idx on log(ts);
CREATE INDEX log_app_idx on log(app);

Perl程序:

use 5.022;
use DBI;

my $DBH = DBI->connect('dbi:SQLite:test.db', '', '', {RaiseError => 1, AutoCommit => 0})
    or die "connect...";

my @apps = (
    '[kthreadd]',        '[ksoftirqd/0]',
     # there were 191 of these
    '[kworker/5:0H]',
);

my @messages = <DATA>;

(my $curr_time) = $DBH->selectrow_array(<<QUERY);
    SELECT COALESCE(MAX(ts),978307200) FROM log
QUERY

my $n_apps = @apps;
my $n_msgs = @messages;
say "Apps: $n_apps";
say "Messages: $n_msgs";
say 'Start time: ', scalar gmtime($curr_time), ' UTC';

my $sth = $DBH->prepare(<<QUERY);
    INSERT INTO log(ts, app, message) VALUES (?, ?, ?)
QUERY

for (my $i = 0; $i < 10_000; ++$i) {
    $sth->execute(int($curr_time), $apps[int rand $n_apps], $messages[int rand $n_msgs]);
    $curr_time += rand 0.1;
}
$DBH->commit;

__DATA__
microcode: CPU0 microcode updated early to revision 0x19, date = 2013-06-21
Linux version 4.5.0-2-amd64 (debian-kernel@lists.debian.org) (gcc version 5.3.1 20160528 (Debian 5.3.1-21) ) #1 SMP Debian 4.5.5-1 (2016-05-29)

有更多示例日志消息(2076)。

检查哪些页面已更改:

cp test.db test.db.old
perl test.pl
cmp -l test.db.old test.db | perl -n -E '/^\s*(\d+) / or die "wtf"; $bucket{int $1/32768} = 1; END { say join "\n", sort( { $a <=> $b } keys %bucket) }'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.