Поведение rsync с файлом, который все еще пишется?

12

Если Apache находится в процессе написания большого файла и для этого файла выполняется задание rsync cron, пытается ли rsync скопировать файл?

пример

  • Apache-1: имеет большой файл для записи /var/www.
  • Apache-2: клон Apache-1. Каждые пять минут cron запускает rsync для /var/wwwсинхронизации.
Луи Ваверу
источник

Ответы:

20

Если Apache записывает какой-то файл в одно место и не завершил его запись, а затем включается rsync, rsyncскопирует все, что там находится.

Это означает, что если Apache имеет дело с 5-мегабайтным файлом, только 2 Мбайт записывается и rsyncзапускается, частичный 2-мегабайтный файл будет скопирован. Таким образом, этот файл может показаться «поврежденным» на конечном сервере.

В зависимости от размера файлов, которые вы используете, вы можете использовать --inplaceопцию в, rsyncчтобы сделать следующее:

Этот параметр изменяет способ, которым rsync передает файл, когда необходимо обновить данные файла: вместо метода по умолчанию для создания новой копии файла и перемещения его на место по завершении, rsync вместо этого записывает обновленные данные непосредственно в место назначения файл.

Преимущество этого состоит в том, что если в файле объемом 5 МБ скопировано только 2 МБ при первом запуске, то при следующем запуске будет загружено 2 МБ и продолжится копирование файла до тех пор, пока не будут заполнены все 5 МБ.

Недостатком является то, что это может создать ситуацию, когда кто-то обращается к веб-серверу во время копирования файла, и тогда он увидит частичный файл. На мой взгляд, rsyncлучше всего работает по умолчанию кэширование «невидимого» файла, а затем сразу же перемещать его на место. Но --inplaceэто хорошо для сценариев, когда большие файлы и ограничения пропускной способности могут помешать тому, чтобы большой файл легко копировался из квадратного.

Это сказало, что Вы заявляете это; Акцент мой

Каждые пять минут cron run rsync…

Итак, я предполагаю, что у вас есть некоторый bash-скрипт для управления этой работой cron? Ну, дело в том, что он rsyncдостаточно умен, чтобы копировать только те файлы, которые нужно скопировать. И если у вас есть скрипт, который запускается каждые 5 минут, похоже, вы пытаетесь не rsyncнаступать друг на друга, если он идет быстрее. Это означает, что если вы запускаете его каждую минуту, существует риск того, что один или несколько rsyncпроцессов все равно будут работать из-за размера файла или скорости сети, и следующий процесс будет просто конкурировать с ним; гоночное состояние.

Один из способов избежать этого - заключить всю rsyncкоманду в скрипт bash, который проверяет блокировку файла; ниже приведен шаблонный сценарий bash, который я использую для подобных случаев.

Обратите внимание, что некоторые люди порекомендуют использовать, flockно так flockкак он не установлен на некоторых системах, которые я использую - и я часто переключаюсь между Ubuntu (у которого он есть) и Mac OS X (без него) - я использую эту простую среду без каких-либо реальных проблем:

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

Идея заключается в том, что общее ядро ​​- где у меня есть echo "Hello world!"- это то, где лежит сердце вашего сценария. В остальном это в основном механизм блокировки / логика на основе mkdir. Хорошее объяснение концепции в этом ответе :

mkdir создает каталог, если он еще не существует, и если он существует, он устанавливает код выхода. Что еще более важно, он делает все это в одном атомном действии, что делает его идеальным для этого сценария.

Так что в случае вашего rsyncпроцесса я бы порекомендовал использовать этот скрипт, просто изменив echoкоманду на вашу rsyncкоманду. Кроме того, измените на LOCK_NAMEчто-то вроде, RSYNC_PROCESSи тогда вы можете идти.

Теперь, когда вы rsyncзавернуты в этот сценарий, вы можете настроить выполнение задания cron каждую минуту без риска возникновения состояния гонки, когда два или более rsyncпроцесса борются за одно и то же. Это позволит вам увеличить скорость или rsyncобновления, что не устранит проблему частичной передачи файлов, но поможет ускорить весь процесс, чтобы в какой-то момент весь файл можно было правильно скопировать.

JakeGould
источник
1
Спасибо за указание на возможность запуска нескольких rsyncs, не думал об этом. Сценарий звучит великолепно. Я просто пытался понять ошибки синхронизации сайта с балансировкой нагрузки с rsync, и это, кажется, облегчает их. Замечательный бонус. Все еще чувствую, что, возможно, это неправильный подход ... но давайте посмотрим :)
Луи Ваверу,
@ Луис Добро пожаловать! Кроме того, если вы хотите синхронизировать папки на основе немедленных изменений файлов, я настоятельно рекомендую изучить вопрос об использовании / адаптации lsyncd. Это позволяет вам иметь «горячие папки», которые действительно обращают внимание на активность в них, а затем воздействуют на эти файлы при внесении изменений. Я использую rsyncмного, как указано в моем ответе, но я использую lsyncdдля случаев, которые требуют не-cron / более немедленной формы действия.
JakeGould
3

Да - и файл может быть поврежден, если rsync читает файл одновременно с записью файла.

Вы можете попробовать это: /unix//a/2558

Вы также можете написать это с помощью lsof:

lsof /path/to file

Код выхода 0 означает, что файл используется, а код выхода 1 означает, что в этом файле нет активности.

rebelshrug
источник
Я не понимаю, почему файл будет поврежден, если rsync просто его читает
orestisf