Comportamento do rsync com o arquivo que ainda está sendo gravado?

11

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: O arquivo grande está sendo gravado em /var/www .
  • Apache-2: clone do Apache-1. A cada cinco minutos, o cron executa o rsync para obter o /var/www sincronizado.
por Louis 03.12.2014 / 07:54

2 respostas

16

Se o Apache está escrevendo um arquivo de algum tipo em um lugar e não completou a gravação e então rsync entra em ação, rsync copiará o que estiver lá.

Significado se o Apache está lidando com um arquivo de 5MB, apenas 2MB é gravado e rsync entra em ação, o arquivo parcial de 2MB será copiado. Então, esse arquivo parece estar "corrompido" no servidor de destino.

Dependendo do tamanho dos arquivos que você está usando, você pode usar a opção --inplace em rsync para fazer o seguinte:

This option changes how rsync transfers a file when the file's data needs to be updated: instead of the default method of creating a new copy of the file and moving it into place when it is complete, rsync instead writes the updated data directly to the destination file.

O benefício disso é que, se um arquivo de 5MB tiver apenas 2MB copiado na primeira execução, a próxima execução será de 2MB e continuará a copiar o arquivo até que os 5MB completos sejam colocados.

O negativo é que poderia criar uma situação em que alguém estivesse acessando o servidor da Web enquanto um arquivo estivesse sendo copiado e, em seguida, veria um arquivo parcial. Na minha opinião, rsync funciona melhor em seu comportamento padrão de armazenar em cache um arquivo "invisível" e depois colocá-lo em prática imediatamente. Mas --inplace é bom para cenários em que grandes arquivos e restrições de largura de banda podem impedir que um arquivo grande seja copiado facilmente do quadrado.

Dito isso, você afirma isso; ênfase é minha:

Every five minutes has cron run rsync…

Então, eu suponho que você tenha algum script básico para gerenciar este trabalho cron? Bem, a coisa é rsync é inteligente 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 que rsync dê passos um para o outro, se for mais rápido. Ou seja, se você executá-lo a cada minuto, há o risco de que um ou mais dos processos rsync continuem sendo executados devido ao tamanho do arquivo ou à velocidade da rede, e o próximo processo estaria apenas em concorrência com ele; uma condição de corrida.

Uma maneira de evitar isso é envolver todo o seu comando rsync em um script bash que verifica um bloqueio de arquivo; abaixo é uma estrutura de script bash boilerplate eu uso para casos como este.

Note que algumas pessoas recomendam usar flock , mas como flock não está instalado em alguns sistemas que eu uso - e eu pulo muito entre o Ubuntu (que tem) e o Mac OS X (o que não) muito - eu use este framework simples sem qualquer 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 ideia é que o núcleo geral - onde eu tenho echo "Hello world!" - é onde está o coração do seu roteiro. O resto é basicamente um mecanismo de travamento / lógica baseado em mkdir . Uma boa explicação do conceito está nesta resposta :

mkdir creates a directory if it doesn't exist yet, and if it does, it sets an exit code. More importantly, it does all this in a single atomic action making it perfect for this scenario.

Portanto, no caso do seu processo rsync , eu recomendaria usar esse script apenas alterando o comando echo para o comando rsync . Além disso, altere o LOCK_NAME para algo como RSYNC_PROCESS e, em seguida, você está pronto.

Agora, com seu rsync agrupado neste script, você pode definir a tarefa cron para ser executada a cada minuto sem qualquer risco de uma condição de corrida em que dois ou mais processos rsync estejam lutando para fazer a mesma coisa. Isso permitirá aumentar a velocidade ou rsync de atualizações, o que não eliminará a transferência de arquivos parciais, mas ajudará a acelerar o processo geral para que o arquivo inteiro possa ser copiado corretamente em algum momento.

    
por 03.12.2014 / 18:59
3

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

Você pode tentar isto: link

Você também pode criar scripts 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.

    
por 03.12.2014 / 18:39