Comportamento de rsync com arquivo que ainda está sendo gravado?

12

Se o Apache estiver no meio da gravação de um arquivo grande e uma tarefa cron do rsync for executada nesse arquivo, o rsync tentará copiar o arquivo?

Exemplo

  • Apache-1: tem um arquivo grande sendo gravado /var/www.
  • Apache-2: Clone do Apache-1. A cada cinco minutos, o cron executa o rsync para ser /var/wwwsincronizado.
Louis Waweru
fonte

Respostas:

20

Se o Apache estiver escrevendo um arquivo de algum tipo em um local e não tiver concluído a gravação e depois rsync entrar em ação, rsynccopiará o que estiver lá.

Ou seja, se o Apache estiver lidando com um arquivo de 5 MB, apenas 2 MB são gravados e rsyncentram em ação, o arquivo parcial de 2 MB será copiado. Portanto, esse arquivo parece estar "corrompido" no servidor de destino.

Dependendo do tamanho dos arquivos que você está usando, você pode usar a --inplaceopção rsyncpara fazer o seguinte:

Esta opção altera a maneira como o rsync transfere um arquivo quando os dados do arquivo precisam ser atualizados: em vez do método padrão de criar uma nova cópia do arquivo e movê-lo para o lugar quando estiver concluído, o rsync grava os dados atualizados diretamente no destino Arquivo.

A vantagem disso é que, se um arquivo de 5 MB tiver apenas 2 MB copiados na primeira execução, a próxima será recuperada com 2 MB e continuará a copiar o arquivo até que os 5 MB completos estejam no local.

O negativo é que isso pode criar uma situação em que alguém está acessando o servidor da web enquanto um arquivo está sendo copiado e então eles vêem um arquivo parcial. Na minha opinião, rsyncfunciona melhor em seu comportamento padrão de armazenar em cache um arquivo "invisível" e depois movê-lo para o lugar imediatamente. Mas --inplaceé bom para cenários em que arquivos grandes e restrições de largura de banda podem impedir que um arquivo grande seja facilmente copiado da estaca zero.

Disse que você afirma isso; ênfase é minha:

A cada cinco minutos , o cron roda o rsync…

Então, suponho que você tenha algum script bash para gerenciar esse trabalho cron? Bem, a coisa é rsyncinteligente o suficiente para copiar apenas os arquivos que precisam ser copiados. E se você tem um script que é executado a cada 5 minutos, parece que você está tentando evitar rsyncentrar um no outro se for mais rápido. Ou seja, se você executá-lo a cada minuto, existe o risco de que um ou mais rsyncprocessos ainda estejam em execução devido ao tamanho do arquivo ou à velocidade da rede e o próximo processo estará apenas em concorrência com ele; uma condição de corrida.

Uma maneira de evitar isso é agrupar todo o rsynccomando em um script bash que verifique se há um bloqueio de arquivo; abaixo está uma estrutura de script bash padrão que eu uso para casos como este.

Observe que algumas pessoas recomendam o uso, flockmas como flocknão está instalado em alguns sistemas que eu uso - e eu pulo muito entre o Ubuntu (que possui) e o Mac OS X (que não possui) - eu uso essa estrutura simples sem nenhum problema real:

LOCK_NAME="MY_GREAT_BASH_SCRIPT"
LOCK_DIR='/tmp/'${LOCK_NAME}.lock
PID_FILE=${LOCK_DIR}'/'${LOCK_NAME}'.pid'

if mkdir ${LOCK_DIR} 2>/dev/null; then
  # If the ${LOCK_DIR} doesn't exist, then start working & store the ${PID_FILE}
  echo $$ > ${PID_FILE}

  echo "Hello world!"

  rm -rf ${LOCK_DIR}
  exit
else
  if [ -f ${PID_FILE} ] && kill -0 $(cat ${PID_FILE}) 2>/dev/null; then
    # Confirm that the process file exists & a process
    # with that PID is truly running.
    echo "Running [PID "$(cat ${PID_FILE})"]" >&2
    exit
  else
    # If the process is not running, yet there is a PID file--like in the case
    # of a crash or sudden reboot--then get rid of the ${LOCK_DIR}
    rm -rf ${LOCK_DIR}
    exit
  fi
fi

A idéia é que o núcleo geral - onde eu tenho echo "Hello world!"- é onde está o coração do seu script. O resto é basicamente um mecanismo / lógica de bloqueio baseado mkdir. Uma boa explicação do conceito está nesta resposta :

O mkdir cria um diretório se ele ainda não existe e, se existir, define um código de saída. Mais importante, ele faz tudo isso em uma única ação atômica, tornando-o perfeito para esse cenário.

Portanto, no caso do seu rsyncprocesso, eu recomendaria o uso desse script apenas alterando o echocomando para seu rsynccomando. Além disso, mude LOCK_NAMEpara algo como RSYNC_PROCESSe então você estará pronto.

Agora, com o seu rsyncenvolto neste script, você pode configurar o cron para executar a cada minuto, sem qualquer risco de uma condição de corrida em que dois ou mais rsyncprocessos estejam lutando para fazer a mesma coisa. Isso permitirá aumentar a velocidade ou as rsyncatualizações, o que não eliminará o problema de transferência parcial de arquivos, mas ajudará a acelerar o processo geral, para que o arquivo completo possa ser copiado adequadamente em algum momento.

JakeGould
fonte
1
Obrigado por apontar a possibilidade de vários rsyncs em execução, não pensei nisso. O script parece ótimo. Eu estava apenas tentando entender as dicas de sincronizar um site com balanceamento de carga com o rsync, e isso parece aliviá-los. Bônus maravilhoso. Ainda sinto que talvez esta é a abordagem errada ... mas vamos ver :)
Louis Waweru
@ Louis Você é bem-vindo! Além disso, se você deseja manter as pastas sincronizadas com base nas alterações imediatas dos arquivos, recomendo que você use / adapte lsyncd. Ele permite que você tenha “hot folders” que realmente prestem atenção à atividade nelas e, em seguida, atuem nesses arquivos quando forem feitas alterações. Eu uso rsyncmuito conforme descrito em minha resposta, mas uso lsyncdem casos que exigem uma forma de ação não cron / mais imediata.
precisa saber é o seguinte
3

Sim - e o arquivo poderá estar corrompido se o rsync estiver lendo o arquivo ao mesmo tempo em que está sendo gravado.

Você pode tentar isso: /unix//a/2558

Você também pode criar um script com lsof:

lsof /path/to file

Um código de saída 0 significa que o arquivo está em uso e o código de saída 1 significa que não há atividade nesse arquivo.

rebelde
fonte
Não vejo por que o arquivo será corrompido se o rsync estiver lendo
seja,