Почему rsync не использует дельта-передачи для одного файла по сети?


15

Я посмотрел на этот вопрос и этот вопрос , но они, кажется, не обращаются к симптомам, которые я вижу.

У меня есть большой файл журнала (около 600 МБ), который я пытаюсь передать по сотовой сети. Потому что это файл журнала он просто добавляется к (хотя это на самом деле в SQLite базе данных только с INSERT выполняется, так что это не совсем так просто, но за исключением последней страницы 4K (или , может быть, несколько) файл каждый раз идентичен. Важно, чтобы только изменения (и любые контрольные суммы, которые необходимо передать) действительно отправлялись, потому что соединение данных измеряется.

Тем не менее, когда я выполняю тестирование по неизмеренному соединению (например, бесплатную точку доступа Wi-Fi), я не вижу ускорения или снижения скорости передачи данных, наблюдаемой или сообщаемой. По медленному WiFi-соединению я вижу порядка 1 МБ / с или меньше, сообщая, что передача займет около 20 минут. По быстрому Wi-Fi-соединению я вижу равномерную более быструю скорость, но нет сообщения об ускорении, и вторая попытка передачи (которая теперь должна быть быстрее, потому что два файла идентичны) теперь показывает какую-то разницу.

Используемая мной (очищенная для удаления конфиденциальной информации) команда:

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)

Там нет упоминаний о каком-либо ускорении.

Я подозреваю, что проблема может быть одной из следующих:

  • Я пропускаю некоторые опции командной строки. Тем не менее, перечитывание справочной страницы говорит о том, что дельта-переносы включены по умолчанию: я вижу только варианты их отключения.
  • Я использую rsync через ssh (даже на нестандартном порту), поскольку сервер находится за брандмауэром, который разрешает только ssh. Я не видел ничего явно говорящего, что дельта-передачи не будут работать, если демон rsync не запущен. Я попытался использовать нотацию «::» вместо «:», но на странице руководства не очень ясно, что такое «модуль», и моя команда отклонена для указания недопустимого модуля.

Я исключил следующее:

  • Переводы дельты не выполняются в локальной сети. Исключен, потому что я пытаюсь выполнить передачу через Интернет
  • накладные расходы из-за вычисления контрольной суммы. Я видел такое поведение как на быстром, так и на медленном Wi-Fi соединении, и скорость передачи данных, похоже, не ограничена вычислительными возможностями.

1
but with the exception of the last 4k page (or maybe a few) the file is identical each time. Вы на самом деле это проверяли cmp? Или лучше, с xdeltaчем-то? Если вы действительно хотите минимизировать размер передачи, сохраняйте старую и новую версии локально, чтобы вы могли локально вычислить минимальный двоичный дифференциал (с чем-то отличным от rsync) и просто отправить его, не отправляя контрольные суммы по измеренному соединению. Делать это на уровне записей базы данных, а не на уровне двоичных файлов, вероятно, еще лучше, как предполагает Дероберт.
Питер Кордес

1
Кроме того, вы могли бы использовать rsync --stats, а также -v -vполучить более подробную статистику. Rsync скажет вам, сколько было сопоставленных и несопоставленных данных.
Питер Кордес

Ответы:


27

Резюме

Базы данных, как правило, содержат много метаданных, организационных данных и т. Д. Вставка, как правило, вряд ли будет простым добавлением, как это было бы с текстовым файлом. Тестирование SQLite показывает, что он ведет себя таким образом, как в WAL, так и в не WAL режимах. Это приводит к тому, что rsync синхронизирует намного больше данных, чем вы ожидаете. Вы можете несколько снизить эти издержки, используя low --block-size(за счет увеличения накладных расходов и передачи контрольных сумм).

Лучший подход, вероятно, состоит в том, чтобы выгружать новые записи как дамп SQL, сжимать их и передавать. В качестве альтернативы, существует несколько решений для репликации SQLite, вы можете использовать одно из них.

roaima предлагает как минимум, вы могли бы сделать полный дамп SQL, сжать его gzip --rsyncable, а затем rsync это. Полагаю, стоит проверить, достаточно ли мала дельта.

Детали

То, что вы пытаетесь, должно работать. Я бы лично добавил --partialк вашим опциям rsync, на случай, если он каким-то образом обнаружит растущий файл как частичную передачу. Вы также можете получить лучшую статистику передачи с --stats.

Во-вторых, нужно проверить, действительно ли SQLite касается только нескольких страниц - честно говоря, я не удивлюсь, если он будет писать страницы по всему файлу. Одним из быстрых способов проверки будет использование cmp -lдвух версий - посмотрите, есть ли изменения на страницах, отличных от последних. Помните, что rsyncидея «страницы» / блока отличается от идеи SQLite; Вы можете изменить Rsync через --block-size. Уменьшение может помочь.

Изменить: я сделал быстрый тест с SQLite. Даже с 32 тыс. Страниц, добавив кучу записей в журнале на каждой странице. Подробности ниже.

Редактировать 2 : Кажется, лучше в режиме WAL, хотя вы по-прежнему берете огромные накладные расходы, вероятно, с контрольной точки.

Изменить 3 : Это также лучше, чем больше данных, которые вы добавляете за передачу - я думаю, что он, вероятно, размечает определенные блоки снова и снова. Таким образом, вы переносите один и тот же набор блоков независимо от того, записал ли он их один или сто раз.

Кстати: для минимизации передачи вы, вероятно, можете сделать намного лучше, чем rsync. Например, дамп SQL новых записей со времени последней передачи xz --best(или даже gzip) будет, вероятно, немного меньше.

Быстрый тест 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) }'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.