Pourquoi rsync n'utilise-t-il pas les transferts delta pour un seul fichier sur un réseau?

15

J'ai regardé cette question et cette question , mais ils ne semblent pas répondre aux symptômes que je vois.

J'ai un gros fichier journal (environ 600 Mo) que j'essaie de transférer sur un réseau cellulaire. Parce qu'il est un fichier journal , il est tout simplement ajouté à (bien qu'il est en fait dans une base de données SQLite avec seulement INSERT en cours d' exécution, il est donc pas tout à fait aussi simple que cela, mais à l'exception de la dernière page 4k (ou peut - être un peu) le fichier est identique à chaque fois. Il est important que seules les modifications (et quelles que soient les sommes de contrôle à transmettre) soient réellement envoyées, car la connexion de données est mesurée.

Pourtant, lorsque j'effectue un test sur une connexion illimitée (par exemple, un point d'accès Wi-Fi gratuit), je ne constate pas d'accélération ou de réduction du transfert de données observé ou signalé. Sur une connexion WiFi lente, je vois de l'ordre de 1 Mo / s ou moins, signalant que le transfert va prendre près de 20 minutes. Sur une connexion WiFi rapide, je vois une vitesse plus rapide uniforme, mais aucun rapport d'accélération, et une deuxième tentative de transfert (qui devrait maintenant être plus rapide car les deux fichiers sont identiques) ne montre désormais aucune différence.

La commande (nettoyée pour supprimer les informations sensibles) que j'utilise est la suivante:

rsync 'ssh -p 9999' --progress LogFile [email protected]:/home/michael/logs/LogFile

La sortie que j'obtiens à la fin ressemble à ceci:

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

Il n'est fait mention d'aucune sorte d'accélération.

Je soupçonne que le problème peut être l'un des suivants:

  • Il me manque une option de ligne de commande. Cependant, relire la page de manuel semble suggérer que les transferts delta sont activés par défaut: je ne vois que les options pour les désactiver.
  • J'utilise rsync sur ssh (sur un port non standard même) car le serveur est derrière un pare-feu qui n'autorise que ssh. Cependant, je n'ai rien vu dire explicitement que les transferts delta ne fonctionneront pas si le démon rsync n'est pas en cours d'exécution. J'ai essayé d'utiliser la notation "::" au lieu de ":" mais la page de manuel n'est pas très claire sur ce qu'est un "module", et ma commande est rejetée pour avoir spécifié un module invalide.

J'ai exclu ce qui suit:

  • transferts delta non effectués sur un réseau local. Exclue parce que j'essaie d'effectuer le transfert sur Internet
  • frais généraux dus au calcul de la somme de contrôle. J'ai vu ce comportement à la fois sur une connexion Wifi rapide et lente et le taux de transfert ne semble pas être lié au calcul.
Michael
la source
1
but with the exception of the last 4k page (or maybe a few) the file is identical each time. Avez-vous réellement vérifié cela avec cmp? Ou mieux, avec xdeltaou quelque chose? Si vous voulez vraiment minimiser la taille du transfert, conservez les anciennes et les nouvelles versions localement, afin de pouvoir calculer un diff binaire minimal localement (avec autre chose que rsync) et l'envoyer sans avoir à envoyer des sommes de contrôle via la connexion mesurée. Faire cela au niveau de l'enregistrement de la base de données au lieu du niveau du fichier binaire est probablement encore mieux, comme le suggère derobert.
Peter Cordes
1
En outre, vous auriez pu utiliser rsync --statset également -v -vobtenir des statistiques encore plus détaillées. Rsync vous dira combien il y avait de données appariées et non appariées.
Peter Cordes

Réponses:

27

Sommaire

Les bases de données ont tendance à conserver un grand nombre de métadonnées, de données organisationnelles, etc. Une insertion est très peu susceptible d'être un simple ajout, comme ce serait le cas avec un fichier texte. Le test de SQLite montre qu'il se comporte de cette façon, en modes WAL et non WAL. Cela conduit à rsync avoir à synchroniser beaucoup plus de données que vous attendez. Vous pouvez réduire quelque peu ces frais généraux en utilisant un faible --block-size(au prix de plus de frais généraux de calcul et de transfert de sommes de contrôle).

Une meilleure approche consiste probablement à vider les nouveaux enregistrements en tant que vidage SQL, à les compresser et à les transférer. Alternativement, il semble y avoir plusieurs solutions de réplication pour SQLite, vous pouvez en utiliser une.

roaima suggère au minimum que vous pourriez probablement faire un vidage SQL complet, le compresser à l'aide gzip --rsyncable, puis le rsync. Ça vaut le coup, je suppose, pour voir si c'est un delta assez petit.

Détails

Ce que vous essayez devrait fonctionner. J'ajouterais personnellement --partialà vos options rsync, juste au cas où il détecterait en quelque sorte le fichier en croissance comme un transfert partiel. Vous pouvez également obtenir de meilleures statistiques de transfert avec --stats.

La deuxième chose à vérifier est de savoir si SQLite ne touche vraiment que quelques pages - honnêtement, je ne serais pas surpris s'il écrit des pages partout dans le fichier. Une façon rapide de vérifier serait d'utiliser cmp -lsur deux versions - voir s'il y a des changements à des pages autres que les dernières. N'oubliez pas que rsyncl'idée d'une "page" / bloc est différente de celle de SQLite; vous pouvez changer via rsync --block-size. La réduire pourrait aider.

Edit: j'ai fait un test rapide avec SQLite. Même avec 32 000 pages, l'ajout d'un tas d'entrées de journal griffonnées sur chaque page. Détails ci-dessous.

Edit 2 : Il semble être meilleur en mode WAL, bien que vous preniez toujours une énorme quantité de frais généraux, probablement du point de contrôle.

Edit 3 : Il est également préférable que plus vous ajoutez de données par transfert - je suppose que cela griffonne certains blocs encore et encore. Vous transférez donc ce même ensemble de blocs, qu'il leur ait écrit une ou cent fois.

BTW: Pour minimiser le transfert, vous pouvez probablement faire beaucoup mieux que rsync. Par exemple, un vidage SQL de nouveaux enregistrements depuis le dernier transfert xz --best(ou même gzip) serait probablement un peu plus petit.

Test SQLite rapide

Schéma:

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);

Programme 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)

Il y avait beaucoup plus d'exemples de messages de journal (2076).

Vérification des pages modifiées:

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) }'
derobert
la source