rsyncがネットワーク上の単一ファイルのデルタ転送を使用しないのはなぜですか?


15

私はこの質問この質問を見てきましたが、彼らは私が見ている症状に対処していないようです。

携帯電話ネットワークで転送しようとしている大きなログファイル(約600 MB)があります。それはそれだけに追加されたログファイルがあるので、それが唯一のINSERTとSQLiteのデータベースに実際にあるが、(それがないので、実行されて、非常にそのような単純な、しかし最後の4Kページの例外を除いて(または多分データ接続が計測されるため、変更(および送信する必要のあるチェックサム)のみが実際に送信されることが重要です。

それでも、従量制の接続(無料のwifiホットスポットなど)でテストを実行しても、データ転送の速度が向上したり、データ転送が減少したりすることはありません。遅いWiFi接続では、1MB / s以下のオーダーで表示され、転送には20分近くかかると報告されています。高速のWiFi接続では、一定の高速化が見られますが、高速化の報告はなく、転送の2回目の試行(2つのファイルが同一であるため、より高速になります)に違いが現れます。

私が使用している(機密情報を削除するためにサニタイズされた)コマンドは次のとおりです:

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のみを許可するファイアウォールの内側にあるため、rsync over ssh(非標準ポートでも)を使用しています。ただし、rsyncデーモンが実行されていない場合、デルタ転送が機能しないことを明示的に示すものは見ていません。「:」の代わりに「::」表記を使用しようとしましたが、マニュアルページでは「モジュール」が何であるかが明確ではなく、無効なモジュールを指定したためにコマンドが拒否されました。

私は以下を除外しました:

  • ローカルネットワークで実行されないデルタ転送。インターネット経由で転送を実行しようとしているため除外
  • チェックサム計算によるオーバーヘッド。高速と低速の両方のWifi接続でこの動作を確認しましたが、転送速度は計算限界ではないようです。

1
but with the exception of the last 4k page (or maybe a few) the file is identical each time. 実際にそれを確認しましたcmpか?またはより良い、xdeltaまたは何か?本当に転送サイズを最小限にしたい場合は、古いバージョンと新しいバージョンをローカルに保持してください。そうすれば、最小のバイナリdiffをローカルで(rsync以外のもので)計算し、従量制接続でチェックサムを送信せずにそれを送信できます。derobertが示唆するように、これをバイナリファイルレベルではなくデータベースレコードレベルで行うことは、おそらくさらに優れています。
ピーターコーデス

1
また、を使用してrsync --stats-v -vさらに詳細な統計情報を取得することもできます。Rsyncは、一致データと不一致データの量を示します。
ピーターコーデス

回答:


27

概要

データベースは、多くのメタデータ、組織データなどを保持する傾向があります。挿入は、テキストファイルの場合のように、単純な追加である可能性は非常に低いです。SQLiteをテストすると、WALモードと非WALモードの両方でそのように動作することがわかります。これにより、rsyncが予想よりもはるかに多くのデータを同期することになります。低い値を使用することで、このオーバーヘッドをいくらか減らすことができます--block-size(オーバーヘッドの計算とチェックサムの転送のコストがかかります)。

より良い方法は、おそらく新しいレコードをSQLダンプとしてダンプし、圧縮して転送することです。別の方法として、SQLiteにはいくつかのレプリケーションソリューションがあるように見えますが、それらの1つを使用できます。

roaimaは、最低限、完全なSQLダンプを実行し、を使用して圧縮しgzip --rsyncable、それをrsync できることを示唆しています。私は、それが十分に小さいデルタであるかどうかを確認する価値があると思います。

詳細

あなたがしようとしているもの動作するはずです。--partial成長中のファイルを部分的な転送として何らかの形で検出する場合に備えて、rsyncオプションに個人的に追加します。また、でより良い転送統計を取得でき--statsます。

2番目に確認することは、SQLiteが実際に数ページにしか触れていないかどうかです。正直なところ、ファイル全体にページを書き込んでいるのであれば、私は驚かないでしょう。チェックする簡単な方法の1つはcmp -l、2つのバージョンで使用することです。最後の数ページ以外のページに変更があるかどうかを確認します。ことを忘れないでくださいrsyncの「ページ"/ブロックは、SQLiteののと異なるのアイデアを。を介してrsyncを変更できます--block-size。それを減らすと役立つかもしれません。

編集: SQLiteで簡単なテストを行いました。32kページであっても、すべてのページで大量のログエントリが追加さます。以下の詳細。

編集2:WALモードのほうが優れているように見えますが、おそらくチェックポイントからはかなりのオーバーヘッドがかかります。

編集3:転送ごとに追加するデータが多いほど優れています。おそらく、特定のブロックを何度も落書きしていると思います。したがって、1回または100回書き込みを行ったかどうかに関係なく、同じブロックのセットを転送しています。

ところで:転送を最小限に抑えるために、おそらく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) }'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.