Pode-se pensar que --link-dest
um arquivo idêntico funcionaria em todos os casos. Mas isso não ocorre quando o arquivo existe, mesmo que esteja desatualizado / com conteúdo diferente.
É por isso, na página de manual do rsync --link-dest
:
"Esta opção funciona melhor ao copiar para uma hierarquia de destino vazia, pois o rsync trata os arquivos existentes como definitivos (para que o rsync nunca procure nos diretórios de destino do link quando um arquivo de destino já existe )"
Isso significa que, se y/file
existir o mesmo que a fonte e z/file
estiver desatualizado,
rsync -a --del -link-dest=y source:/file z
resultará na utilização de DOIS inodes (e duas vezes o espaço em disco) y/file
e z/file
, que terão o mesmo conteúdo e carimbos de dados.
Me deparei com isso porque faço backups diários basicamente com esse script executado uma vez por dia:
mv $somedaysago $today;
yest=$today; today=`date +%Y%m%d`;
rsync -avPShyH --del --link-dest=../$yest host:/dirs $today
Como meus backups abrangem até 10 milhões de arquivos, a execução rm -rf $olddir; rsync source:$dir newdir
levaria muito tempo (especialmente quando apenas 0,5% dos arquivos são alterados por dia, incorrendo na exclusão e criação de entradas de 10 milhões de diretórios apenas para lidar com 50 mil arquivos novos ou alterados, o que tornaria meu backups não concluídos a tempo para o dia seguinte).
Aqui está uma demonstração da situação:
a
é a nossa fonte, 1
através de 4
nossos backups numerados:
$ mkdir -p 1 2; echo foo > 1/foobar; cp -lrv 1/* 2
`1/foobar' -> `2/foobar'
$ ls -i1 */foobar
1053003 1/foobar
1053003 2/foobar
$ mkdir a; echo quux > a/foobar
$ mv 1 3; rsync -avPhyH --del --link-dest=../2 a/ 3
sending incremental file list
./
foobar
5 100% 0.00kB/s 0:00:00 (xfer#1, to-check=0/2)
sent 105 bytes received 34 bytes 278.00 bytes/sec
total size is 5 speedup is 0.04
$ ls -i1 */foobar
1053003 2/foobar
1053007 3/foobar
1053006 a/foobar
$ mv 2 4; rsync -avPhyH --del --link-dest=../3 a/ 4
sending incremental file list
./
foobar
5 100% 0.00kB/s 0:00:00 (xfer#1, to-check=0/2)
sent 105 bytes received 34 bytes 278.00 bytes/sec
total size is 5 speedup is 0.04
$ ls -il1 */foobar
1053007 -rw-r--r-- 1 math math 5 Mar 30 00:57 3/foobar
1053008 -rw-r--r-- 1 math math 5 Mar 30 00:57 4/foobar
1053006 -rw-r--r-- 1 math math 5 Mar 30 00:57 a/foobar
$ md5sum [34a]/foobar
d3b07a382ec010c01889250fce66fb13 3/foobar
d3b07a382ec010c01889250fce66fb13 4/foobar
d3b07a382ec010c01889250fce66fb13 a/foobar
Agora, temos dois backups a/foobar
idênticos em todos os aspectos, incluindo carimbo de data e hora, mas ocupando inodes diferentes.
Pode-se pensar que seria uma solução --delete-before
, que mata os benefícios da varredura incremental, mas isso não ajuda, pois o arquivo não será excluído, mas usado como base no caso de uma cópia incremental ser possível.
Pode-se supor ainda mais, então podemos desativar esse hedge de cópia incremental --whole-file
, mas isso não ajuda o algoritmo, não há como obter o que queremos.
Considero esse comportamento outro bug no rsync, onde um comportamento benéfico pode ser interpretado a partir de seleções cuidadosas de vários argumentos de comando, mas o resultado desejado não está disponível.
Infelizmente, uma solução seria passar de um único rsync como uma operação atômica para uma execução a seco -n
, registrando-a, processando esse log como entrada para pré-excluir manualmente todos os arquivos alterados e executando rsync --link-dest
para obter o que queremos - um grande argumento comparado a um único rsync limpo.
Adendo: tentou pré-vincular $yesterday
e $today
no servidor de backup antes do backup às caixas de produção com rsync --link-dest=../$yesterday $yesterday/ $today
- mas o mesmo resultado - qualquer arquivo que exista de qualquer forma, mesmo com 0 comprimento, nunca será removido e será destinado ao link, em vez de um todo uma nova cópia será feita a partir do fornecedor com um novo inode e utilizando mais espaço em disco.
Considerada pax(1)
uma possível solução de pré-vinculação antes do backup.
--delete-after
está bem, mas não está relacionado ao problema em questão. Os arquivos ausentes da fonte serão excluídos após a conclusão da cópia. O problema que estou elucidando refere-se a um backup que está sendo feito hoje, idêntico ao de ontem, mas contra um arquivo desatualizado existente antigo, que não está vinculado ao inode de ontem, mas armazenado como um novo arquivo com o dobro do espaço total em disco do dia anterior. cópia idêntica é considerada.
rsnapshot
? Além disso, considere escrever um pequeno script para vincular novamente arquivos "idênticos". Eu faço as duas coisas nos meus sistemas.
hardlink(1)
é lento (15x mais lento que a verificação de metadados do rsync); pax
é mais rápido, mas supera as cabeças dos discos rígidos, comparando o backup antigo com o novo. rsync -n
obter a lista delta significa atingir os servidores de produção duas vezes (a digitalização de 10 milhões de arquivos é muito mais impactante do que copiar as alterações de 50 mil). Enviarei a lista por e-mail sobre uma opção no rsync para permitir isso.
--delete-after
neste cenário de uso, o que há de errado nisso?