Por que o rsync não está usando transferências delta para um único arquivo em uma rede?

15

Analisei esta pergunta e esta pergunta , mas eles não parecem abordar os sintomas que estou vendo.

Eu tenho um arquivo de log grande (cerca de 600 MB) que estou tentando transferir através de uma rede celular. Como é um arquivo de log, ele é apenas anexado (embora esteja em um banco de dados SQLite com apenas INSERT sendo executado, portanto, não é bastante tão simples quanto isso, mas com a exceção do A última página 4k (ou talvez algumas) o arquivo é idêntico a cada vez.É importante que somente as mudanças (e quaisquer somas de verificação que precisam ser transmitidas) sejam realmente enviadas, porque a conexão de dados é medida.

No entanto, quando realizo um teste em uma conexão não monitorada (por exemplo, hotspot de Wi-Fi gratuito), não vejo uma transferência de dados acelerada ou reduzida observada ou relatada. Sobre uma conexão WiFi lenta eu vejo na ordem de 1MB / s ou menos, informando que a transferência vai levar quase 20 minutos. Em uma conexão WiFi rápida, vejo uma velocidade uniforme mais rápida, mas nenhum relatório de aceleração, e uma segunda tentativa de transferência (que agora deve ser mais rápida porque os dois arquivos são idênticos) agora mostra alguma diferença.

O comando (limpo para remover informações confidenciais) que estou usando é:

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

A saída que recebo no final é assim:

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

Não há menção a qualquer tipo de aceleração.

Suspeito que o problema pode ser um dos seguintes:

  • Estou sentindo falta de alguma opção de linha de comando. No entanto, a releitura da página man parece sugerir que as transferências delta são ativadas por padrão: vejo apenas opções para desabilitá-las.
  • Estou usando o rsync sobre o ssh (em uma porta não padrão até) devido ao servidor estar atrás de um firewall que permite apenas o ssh. Eu não vi nada explicitamente dizendo que as transferências delta não funcionarão se o daemon rsync não estiver rodando, no entanto. Eu tentei usar a notação "::" em vez de ":", mas a página man não é muito clara sobre o que é um "módulo", e meu comando é rejeitado por especificar um módulo inválido.

Eu descartei o seguinte:

  • transferências delta não realizadas em uma rede local. Excluído porque estou tentando realizar a transferência pela Internet
  • Sobrecarga
  • devido ao cálculo da soma de verificação. Eu já vi esse comportamento em uma conexão Wi-Fi rápida e lenta, e a taxa de transferência não parece estar vinculada à computação.
por Michael 25.07.2016 / 17:05

1 resposta

26

Resumo

Bancos de dados tendem a manter muitos metadados, dados organizacionais, etc. Uma inserção é muito improvável que seja um simples acréscimo, como seria com um arquivo de texto. O teste do SQLite mostra que ele se comporta dessa maneira, nos modos WAL e não-WAL. Isso faz com que o rsync tenha que sincronizar muito mais dados do que você espera. Você pode reduzir um pouco essa sobrecarga usando um --block-size baixo (ao custo de mais computação de sobrecarga e transferência de somas de verificação).

Uma abordagem melhor é provavelmente despejar novos registros como um dump SQL, compactá-lo e transferi-lo. Como alternativa, parece haver várias soluções de replicação para o SQLite, você pode usar uma delas.

roaima sugere que, no mínimo, você provavelmente poderia fazer um despejo SQL completo, compactá-lo usando gzip --rsyncable e, em seguida, rsync isso. Vale a pena testar, suponho, para ver se é um delta pequeno o suficiente.

Detalhes

O que você está tentando deve funcionar. Eu pessoalmente adicionaria --partial às suas opções de rsync, para o caso de de alguma forma detectar o arquivo crescente como uma transferência parcial. Você também pode obter estatísticas de transferência melhores com --stats .

A segunda coisa a verificar é se o SQLite está realmente tocando apenas algumas páginas - honestamente, eu não ficaria surpreso se ele estivesse escrevendo páginas por todo o arquivo. Uma maneira rápida de verificar seria usar cmp -l em duas versões - ver se há alterações em outras páginas além das finais. Lembre-se que a idéia de% " rsync " de uma "página" / bloco é diferente da do SQLite; você pode mudar o rsync via --block-size . Reduzir isso pode ajudar.

Edit: Eu fiz um teste rápido com o SQLite. Mesmo com 32k páginas, adicionando um monte de entradas de log rabiscadas na página every . Detalhes abaixo.

Editar 2 : Parece ser melhor no modo WAL, embora você ainda tenha uma enorme sobrecarga, provavelmente do ponto de verificação.

Editar 3 : Também é melhor quanto mais dados você adicionar por transferência, acho que provavelmente rabisca alguns blocos repetidas vezes. Então você está transferindo o mesmo conjunto de blocos, independentemente de ter escrito para eles uma ou cem vezes.

BTW: Para minimizar a transferência, você provavelmente pode fazer muito melhor que o rsync. Por exemplo, um despejo SQL de novos registros desde a última transferência executada por xz --best (ou mesmo gzip ) provavelmente seria um pouco menor.

Teste rápido de SQLite

Esquema:

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

Programa 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 ([email protected]) (gcc version 5.3.1 20160528 (Debian 5.3.1-21) ) #1 SMP Debian 4.5.5-1 (2016-05-29)
⋮

Havia muito mais mensagens de log de exemplo (2076).

Verificando quais páginas foram alteradas:

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) }'
    
por 25.07.2016 / 17:23

Tags