概要
データベースは、多くのメタデータ、組織データなどを保持する傾向があります。挿入は、テキストファイルの場合のように、単純な追加である可能性は非常に低いです。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) }'
but with the exception of the last 4k page (or maybe a few) the file is identical each time.
実際にそれを確認しましたcmp
か?またはより良い、xdelta
または何か?本当に転送サイズを最小限にしたい場合は、古いバージョンと新しいバージョンをローカルに保持してください。そうすれば、最小のバイナリdiffをローカルで(rsync以外のもので)計算し、従量制接続でチェックサムを送信せずにそれを送信できます。derobertが示唆するように、これをバイナリファイルレベルではなくデータベースレコードレベルで行うことは、おそらくさらに優れています。