11

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

пример

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

2 ответа2

17

Если 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 что не устранит проблему частичной передачи файлов, но поможет ускорить весь процесс, чтобы в какой-то момент весь файл можно было правильно скопировать.

3

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

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

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

lsof /path/to file

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .