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

HTTP-сервер Apache - как определить на сервере, завершена ли загрузка и какой файл?

У нас есть запущенный и работающий HTTP-сервер Apache, который обслуживает пользователей динамически создаваемых zip-архивов, размер которых может составлять несколько сотен мегабайт. Поскольку мы создаем новый файл при каждом нажатии кнопки «загрузить» (даже если содержимое не изменилось ...), мы, скорее всего, столкнемся с проблемами емкости диска.

У меня запущен довольно тупой скрипт, который удаляет все файлы, созданные более 90 минут назад. Очевидно, не такое уж хорошее решение.

Мне было интересно, как определить из командной строки сервера, когда загрузка завершилась успешно или нет. В этом случае я могу удалить этот файл, поскольку он не будет обслуживаться дважды. Подумав об этом, может быть даже достаточно проверить, использует ли сервер файл или нет, поскольку он создается прямо перед тем, как он будет передан клиенту.

Спасибо!

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

У TRS-80 правильная идея, и я определенно рекомендую пойти по этому пути. Если вы настроены ждать завершения передачи, подумайте об использовании lsof чтобы определить, когда никто не открыл файл. Итак, что-то вроде:

for file in /directory/full/of/zips/*.zip; do
  if [ -z "$(lsof $file)" ]; then
    # Nobody's reading it, delete
    rm $file
  fi
done

Первый способ, который я вижу, - это проанализировать результат Статус сервера чтобы узнать, началась ли загрузка. Когда загрузка началась, вы можете удалить файл, как сказал TRS-80. Но я бы не рекомендовал это, потому что, если ваш клиент отключился по какой-либо причине, он не сможет перезапустить загрузку. Поэтому я бы проанализировал файл журнала, чтобы узнать, когда файл был загружен. Запись в файл журнала не будет добавлена, пока соединение с клиентом не будет закрыто. В файле журнала у вас будет номер октета, обслуживаемого клиентом, чтобы вы могли сравнить его с размером файла, чтобы быть уверенным, что он загрузил весь файл.

Я бы предложил более элегантное решение:

Apache может вести условное ведение журнала, и журнал может быть выведен в процесс. Итак, вы можете сделать что-то вроде:

SetEnvIf Request_URI "^/path/to/files/.*\.zip$" deletefile
CustomLog "|/path/to/program" "%r" env=deletefile

Программа получит имя файла после завершения каждого запроса и может удалить его:

#!/usr/bin/perl
$| = 1;
while (<STDIN>) {
    unlink($_);
}

Вы даже можете использовать "%> s% r" в качестве формата и удалять, только если статус равен 200.

Это не окончательный ответ, но как я сначала подумаю об этом.

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

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

Во-первых, вы должны убедиться, что вы делаете что-то таким образом, чтобы Apache мог использовать Отправить файл. Я также был бы обеспокоен созданием файла с помощью любого уровня приложения на основе модуля, mod_php, mod_python или обратного прокси-сервера для mongrel / Ruby on Rails. Вы действительно нужно быть осторожным с этим. Я мало что знаю о вашей настройке, но инстинкт подсказывает мне, что вам следует:

  1. Используйте рабочий MPM вместо Pre-Fork
  2. При использовании Python см.: WSGI При использовании PHP см.: FastCGI Если Rails видит: Пассажир
  3. Не позволяйте пользователям запрашивать, что запускает генерацию файла - сделайте доставку. Используйте шаблон, подобный AJAX, чтобы:
    1. Создание очереди файла
    2. Периодически проверяйте выполнение
    3. Лог, что загрузка началась (ну вот-вот)
    4. Начать скачивание
  4. Однако не полагайтесь на то, что клиент укажет вам, что вы должны удалить файл. Я бы периодически использовал lsof в "начатом журнале" для удаления.

Конечно, в моей отрасли нам всегда приходится беспокоиться о возможности масштабирования. Вам может быть все равно.

Как другой вариант - у меня аналогичный процесс, но я ничего не записываю на диск, так как обслуживаю архивы размером в несколько ГБ.

Вместо этого я просто отправляю соответствующие HTTP-заголовки (включая Content-Disposition для установки имени файла), а затем передаю их в zip (или tar) с соответствующими флагами для записи в стандартный вывод.

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

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