Назад | Перейти на главную страницу

Как атомарно заменить файлы в Apache?

Когда я заменяю обслуживаемый файл (или изменяю символическую ссылку) и одновременно загружаю этот файл, Apache редко (в небольшой доле процента) отвечает заголовками из старого файла, но с содержимым из нового файла.

Я тестировал его на нескольких версиях Apache 2.2 (2.2.3, 2.2.22 - Debian стабильный), локально и удаленно, на виртуальных и физических машинах, в разных дистрибутивах (Red Hat, CentOS, Debian) - я всегда мог воспроизвести его, используя Скрипт Python многократно загружает файл в потоках (20-200 потоков) и время от времени заменяет его на сервере (например, каждые 100 мс).

В чем проблема? Это вина Apache или, может быть, я что-то делаю не так?

Обновить: Я также тестировал Nginx, у него этой проблемы нет. Но в редких случаях (в 100 раз реже, чем на Apache) он не видит файл и обслуживает содержимое по умолчанию (404 или страница по умолчанию).

Вместо того, чтобы возиться с файловой системой, я предлагаю изменить конфигурацию сервера, т.е.

DocumentRoot /var/www/version_1

к

DocumentRoot /var/www/version_2

а затем испустить apachectl -k gracefull. Использование include - это всего лишь небольшой фрагмент, который нужно перезаписать. Очевидно, что все еще существует период, когда некоторые процессы apache могут обслуживать старые файлы со старыми заголовками, а другие - новые файлы с новыми заголовками, но проблемы смешанных заголовков / содержимого возникнуть не должно.

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

В POSIX-совместимых системах переименование выполняется атомарно. Таким образом, должно быть безопасно и последовательно записывать в filename.new, а затем в "mv filename.new filename". Любые открытые дескрипторы в «старом» имени файла будут получать содержимое в старом индексном дескрипторе, а новые запросы получат новый.