Usando o rsync para carregar rapidamente um arquivo semelhante a outro arquivo

6

Estou montando um script de implantação que divide um diretório do meu código, nomeia o arquivo tar após a data e hora atuais, envia-o para o servidor, desvia-o em um diretório com o mesmo nome e troca um symlink "atual" para apontar para o novo diretório. Isso significa que minhas implantações mais antigas permanecem em diretórios com timestamp (pelo menos até que eu os exclua).

O arquivo tar tem cerca de 5MB e leva quase um minuto para ser transferido. Eu gostaria de acelerar isso.

Eu assumo que cada novo tarball é bastante similar em estrutura ao tarball anterior (já que muitas vezes eu estou apenas alterando algumas linhas de código-fonte entre as implementações). Existe uma maneira de aproveitar este fato para acelerar meus uploads usando o rsync?

Idealmente eu gostaria de dizer "hey rsync, faça o upload deste arquivo local chamado 2009-10-28-222403.tar.gz para o meu servidor, mas é apenas um pouquinho diferente do arquivo 2009-10-27- 101155.tar.gz que já está lá em cima, então tente apenas enviar as diferenças ". Isso é possível, ou há outra ferramenta que eu deveria estar olhando?

    
por Simon Willison 29.10.2009 / 00:03

10 respostas

6

I'm putting together a deployment script which tars up a directory of my code, names the tar file after the current date and time, pushes that up to the server, untars it in a directory of the same name and then swaps a "current" symlink to point at the new directory.

Pessoalmente, acho que você deveria pular o uso de tar e, em vez disso, olhar o recurso --link-dest ou --copy-dest de rsync . A função de link-dest é muito legal, ele saberá olhar para a sincronização anterior do diretório, e se os arquivos forem idênticos, eles irão dificultar a vinculação entre eles, ignorando a necessidade de retransferir o arquivo toda vez.

mkdir -p /srv/codebackup/2009-10-12 \
         /srv/codebackup/2009-10-13

# first backup on 10-12
rsync -a sourcehost:/sourcepath/ \
         /srv/codebackup/2009-10-12/

# second backup made on 10-13
rsync -a --link-dest=/srv/codebackup/2009-10-12/
         sourcehost:/sourcepath/ \
         /srv/codebackup/2009-10-13/

Sua segunda execução do rsync só transferirá arquivos alterados. Arquivos idênticos serão vinculados em conjunto. Você pode excluir a árvore mais antiga e o novo backup ainda estará 100% concluído. Você economizará muito espaço de armazenamento, já que não manterá várias cópias de arquivos idênticos.

    
por 29.10.2009 / 07:01
3

rsync AFAIK não pode fazer isso diretamente, mas você pode estruturar seus tarballs para fazer com que eles sejam transferidos mais rapidamente, aproveitando o fato de que eles são semelhantes.

Confira o sinalizador --resyncable do gzip. Do manual:

While compressing, synchronize the output occasionally based on the input. This increases size by less than 1 percent most cases, but means that the rsync(1) program can much more efficiently synchronize files compressed with this flag. gunzip cannot tell the difference between a compressed file created with this option, and one created without it.

Isso fará com que seus tarballs similares sejam realmente mais semelhantes, de modo que o rsync os reconheça.

Você provavelmente teria que modificar um pouco seus scripts de implantação para reduzir a quantidade de transferência, porque eu não acho que o rsync pode ser instruído a "olhar para outro arquivo" ... o que eu faço é sempre rsync algo chamado current.tar.gz (compactado com gzip e o sinalizador acima) e renomeie-o para propósitos de arquivamento no servidor. Isso, ou renomear um tarball antigo no servidor para o nome do tarball que está prestes a ser carregado, para que o rsync possa usá-lo.

    
por 29.10.2009 / 00:18
3

Acho que usar o tar aqui é a resposta errada. O que eu faria, para este caso em particular, é cp -rp seu código "atual" no servidor para um diretório datado. Então rsync sua verificação de código local contra "atual". Então basicamente isso:

  1. usuário ssh @ host cp -rp / path / to / current / path / to / 2009-10-28 /

  2. rsync / local / copy usuário @ host: / caminho / para / atual

Isso lhe dá a cópia de backup que você quer, sincroniza suas alterações e será muito mais rápido que tar + scp + untar.

Espero que ajude!

    
por 29.10.2009 / 00:25
2

Ok, eu não tentei isso, mas seria interessante ver como isso funciona no seu caso.

Você desejará minimizar as alterações em cada chamada de tar. Ajudaria a garantir que os arquivos estivessem sempre na mesma ordem em cada instância. Você pode então compactar com a opção --rsyncable .

Você pode encomendar os arquivos pela data da última modificação? Dessa forma, os arquivos que não são alterados estão sempre na mesma ordem e no início, e os arquivos que são alterados estão no final, portanto, quando eles mudam de tamanho, eles não quebram o algoritmo de bloqueio.

tar cvf - -T 'find . -type f | xargs ls --sort=time -r' | gzip -9 --rsyncable

Outra coisa a considerar é que tar suporta o bloqueio e preencherá cada arquivo com nulos para um deslocamento de bloco. Verifique os tamanhos de blocos . Você poderia definir isso para o tamanho do bloco rsync (ah, isso depende do tamanho do arquivo, erm como 8k?). O que ajudará o algoritmo quando um único arquivo for reordenado. Agora, solte o gzip em cada extremidade (gzip o último, mas um no servidor, se você está preocupado com o espaço em disco), e eu acho que você pode obter a velocidade que você deseja.

Não estou tão impressionado com a opção --rsyncable . Eu estou usando isso em postgres dumps diários, e descubro que, embora apenas uma pequena quantidade do dump mude a cada dia, rsync usa cerca de metade da largura de banda de apenas copiar o .gz ao redor. Eu poderia fazer uma pergunta sobre isso, na verdade.

Acho que você será o melhor com o rsync eficiente de arquivos individuais incluídos em outras respostas e, em seguida, gerando o .tar.gz do diretório resultante no servidor (ou o cliente, se for onde você deseja manter seu arquivo). O que há de errado com o seu sistema de controle de versão, como um registro do que você implantou quando? Você não está implantando código não confirmado, está?

    
por 03.11.2009 / 23:10
2

Você pode procurar no modo fuzzy do rsync (ativado com a opção --fuzzy )

Isso permite que o rsync selecione um arquivo no sistema de destino que seja semelhante ao arquivo que está sendo transferido e use esse arquivo como base para aplicar o algoritmo de upload delta. É um pouco de memória e de E / S com fome, especialmente se você tiver um diretório grande no lado do destino, mas deve fornecer as melhorias de upload que você está procurando, sem ter que reajustar sua abordagem como outras respostas sugeriram.

    
por 09.09.2010 / 19:59
1

O que tem que ser um arquivo tar? Por que não rsync o código para o seu diretório de implantação e usar o tar como backup?

    
por 29.10.2009 / 00:18
1

Isso não está diretamente relacionado, já que não aborda a solução rsync , mas pode ajudar um pouco com o tamanho do arquivo: você já tentou usin bzip2 compression em vez de gzip ?

Em vez de tar czvf blah.tar.gz files , você pode fazer tar cjvf blah.tar.bz2 files e obter uma melhor compressão (supondo que você tenha o bzip2 instalado, é claro).

    
por 29.10.2009 / 00:19
1

Simon: repetindo a mesma questão mencionada acima ... alguma razão pela qual precisar de alcatrão em primeiro lugar?

    
por 29.10.2009 / 00:27
1

use hardlinks para copiar e transferir apenas os diffs; exemplo: cp -lr old_date_dir / new_date_dir / (isso está no "servidor") servidor de código rsync -ax --numeric-ids: / path / new_date_dir /

isso funcionará porque o rsync é desvinculado antes de transferir os diffs.

    
por 29.10.2009 / 00:41
1

As outras soluções ignoram o motivo pelo qual você queria usar o rsync em primeiro lugar, ou seja, apenas enviando os arquivos que foram alterados. Que tal abordá-lo de forma ligeiramente diferente, evitando tarballs no processo, mas mantendo os benefícios do rsync e rollbacks.

Primeiro, no seu host remoto, crie um diretório recente para o rsync:

mkdir /var/www/recent

Em seguida, crie um symlink para apontar para este diretório:

ln -s /var/www/recent /var/www/active 

Configure o Apache para servir arquivos em / var / www / active

Em seguida, rsync sua pasta local para seu host remoto:

rsync -v -r --delete ~/Sites/Foo/ foo.org:/var/www/recent

Em seguida, faça backup do diretório remoto, remotamente:

ssh foo.org cp -R /var/www/current /var/www/'date +%Y%m%d%H%M%S'

Agora, depois de um tempo, seu diretório / var / www remoto deve ser parecido com:

/var/www/200909041234
/var/www/200910121712
/var/www/200911030446
/var/www/active
/var/www/recent

Se você precisar reverter, mude o link simbólico:

ssh foo.org ln -s /var/www/200911030446 /var/www/active

Fácil pechincha!

Para pontos de bônus:

  1. Abra o Automator
  2. Crie um novo serviço
  3. Crie uma nova ação para executar um script de shell
  4. Plop o comando rysnc e os comandos de cópia do diretório remoto para esta janela
  5. Salve o fluxo de trabalho como "Publicar o site Foo"
  6. Ir para as Preferências do Sistema
  7. Ir para as preferências de teclado
  8. Ir para serviços
  9. Encontre o serviço Publicar site do Foo e vincular a um atalho de chave

Publicação automatizada de qualquer aplicativo no OS X!

    
por 29.10.2009 / 00:36