Почему Apache не рекомендует использовать sendfile() с NFS в Linux

Документация Apache включает этот оператор для EnableSendfile:

При смонтированном в сети DocumentRoot (например, NFS, SMB, CIFS, FUSE) ядро ​​может быть не в состоянии обслуживать сетевой файл через собственный кэш.[1]

Конфигурация по умолчанию для Apache 2.4 и Nginx отключает sendfile().

Я пытаюсь найти что-то конкретное, описывающее точную проблему при использовании sendfile() с файловыми системами NFS в Linux. Запуск минимальной тестовой программы на ядре 3.10.0-327.36.3 (CentOS 7) подтверждает, что sendfile() работает, когда источник находится в NFS, и считывается из кеша страниц (первый запуск медленный, затем быстрый, drop_caches, чтобы снова сделать его медленным, то есть перечитать из исходного кода). Я пробовал с размерами файлов до 1G, и все, казалось, работало нормально. Я предполагаю, что должен быть какой-то набор обстоятельств, который выявляет ошибочное поведение, но я хотел бы точно знать, что это такое.

Для сравнения, есть некоторая документация о проблемах томов VirtualBox с sendfile()[2], но я не могу найти что-то похожее, касающееся Apache, или как воспроизвести проблемную конфигурацию.


person protospark    schedule 22.09.2017    source источник


Ответы (2)


Конфигурация по умолчанию для Nginx включает sendfilehttps://github.com/nginx/nginx/blob/release-1.13.8/conf/nginx.conf#L27, поэтому я запутался в вашем заявлении.

Еще в начале 2000-х вы могли видеть, как разработчик Apache представил возможность отключения SendFile ( и вот сообщение списка рассылки для патча< /а>). Также есть старые ошибки, которые могли быть связаны с sendfile, в системе отслеживания ошибок Apache. Из ошибки Apache #12893 мы узнаем, что одна из наблюдаемых ошибок была вызвана тем, что реализация NTFS в ядре Linux просто вообще не поддерживала системный вызов sendfile:

[...] очевидно, есть какая-то характеристика вашей файловой системы NTFS, которая мешает работе sendfile().

sendfile(8, 9, [0], 9804)               = -1 EINVAL (Invalid argument)

В сообщении в блоге под названием "Загадочная история Sendfile и Apache" упоминается вопрос stackoverflow, который вы читаете, выдвигает следующую теорию:

sendfile() передаст не более 0x7ffff000 (2 147 479 552) байт, возвращая количество фактически переданных байтов. (Это справедливо как для 32-разрядных, так и для 64-разрядных систем.)

Есть ограничение в 2 Гб. Теперь вот предположение, в документации apache говорится:

При смонтированном в сети DocumentRoot (например, NFS, SMB, CIFS, FUSE) ядро ​​может быть не в состоянии обслуживать сетевой файл через собственный кэш[2].

Поэтому, когда говорится, что «ядро может быть не в состоянии обслужить файл», я думаю, мы можем иметь в виду внутреннее ограничение на размер файла, которое имеет sendfile.

Интересная теория, но я сомневаюсь, что это ответ, потому что вы можете просто не использовать путь кода sendfile для слишком больших файлов. Обновление: копаясь, я обнаружил, что автор этого поста создал продолжение под названием В тот раз, когда я ошибался в отношении Sendfile() и Apache, в котором упоминается ответ, который вы читаете!

В документации ProFTPD также есть предупреждения о проблемах с файлом отправки:

Были случаи, когда именно файловые системы, а не ядра, были виновниками проблем sendfile(2):

  • Сетевые файловые системы (например, NFS, SMBFS/Samba, CIFS)
  • Виртуализированные файловые системы (OpenVZ, VMware и даже Veritas)
  • Другие файловые системы (например, NTFS и tmpfs в Linux)

Опять же, если вы столкнулись с проблемами при загрузке файлов из ProFTPD, когда эти файлы находятся в сетевой или виртуализированной файловой системе, попробуйте использовать «UseSendfile off» в вашем proftpd.conf.

Много предупреждений "здесь будут драконы". Некоторые из них будут вызваны тем, что файловая система просто не поддерживает sendfile (например, до 2.4.22-pre3 Linux tmpfs не поддерживал sendfile). Файловые системы на основе FUSE (такие как NTFS-3g) также имели бы проблемы в прошлом из-за ошибок FUSE и sendfile (с тех пор, как они были устранены). Хотя список виртуализированных файловых систем является интересным дополнением...

Однако Часто задаваемые вопросы по OrangeFS, похоже, содержат наиболее правдоподобное объяснение:

5.16 Можем ли мы запустить веб-сервер Apache для обслуживания файлов с тома OrangeFS?

Что вы можете! Однако мы рекомендуем отключить параметр EnableSendfile в файле httpd.conf перед запуском веб-сервера. В качестве альтернативы вы можете настроить OrangeFS с опцией -enable-kernel-sendfile. Передача этой опции для настройки приводит к тому, что модуль ядра Orangefs поддерживает обратный вызов sendfile. Но мы рекомендуем, если обслуживаемые файлы не достаточно велики, это может быть не очень хорошей идеей с точки зрения производительности. Apache 2.x+ использует системный вызов sendfile, который обычно передает данные файла через кэш страницы. В последних ядрах 2.6 этого можно избежать, предоставив процедуру обратного вызова sendfile в файловой системе. Следовательно, это гарантирует, что мы не получим устаревшие или несогласованные кэшированные данные в таких ядрах. Однако в более старых ядрах 2.4 системный вызов sendfile передает данные через кэш страниц, и поэтому существует реальная вероятность того, что данные будут обслуживаться устаревшими. Поэтому пользователи системного вызова sendfile должны быть осторожны с этой деталью.

Аналогичное объяснение можно прочитать в системный вызов Linux guest readv возвращает устаревшие (кэшированные) данные файла общей папки с ошибкой Virtualbox< /а>:

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

[...]

использование функции ядра generic_file_read_iter в качестве члена .read_iter структуры file_operations (.read_iter используется при выполнении системного вызова readv). Эта функция БУДЕТ записывать и читать из файлового кеша. Однако функция vbox sf_reg_read, используемая для универсального члена .read и системного вызова чтения, по-видимому, всегда обходит кэш файловой системы Linux.

[...]

Кроме того, я считаю, что аналогичная долгоживущая проблема сообщается как билет #819, только для файла отправки. системный вызов. Кажется, что все эти функции generic_file_* предполагают, что хост контролирует весь доступ к диску.

Вышеизложенное также может объяснить список проблемных файловых систем виртуализации ProFTPD.

Резюме (наилучшее предположение)

Apache не рекомендует использовать sendfile() с Linux NFS, потому что их программное обеспечение популярно и вызвало множество болезненных для отладки ошибок, связанных с sendfile, в старых клиентах Linux NFS. Предупреждение устарело, и, вероятно, проще оставить его как есть, чем обновлять со всеми предостережениями.

Если у вас есть файловая система Linux, в которой базовые данные могут быть изменены без аннулирования кеша страниц Linux, неразумно использовать sendfile с ним в старых ядрах Linux (это объясняет проблемы старых клиентов Linux NFS). С более новыми ядрами, если вышеупомянутая файловая система не реализует собственный хук sendfile, снова использовать sendfile неразумно (проблема с общей папкой Virtualbox демонстрирует это).

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

person Anon    schedule 02.01.2018

Я думаю, что вижу, где может возникнуть некоторая путаница с Nginx.

В документации Nginx указано следующее: https://docs.nginx.com/nginx/admin-guide/web-server/serving-static-content/:

По умолчанию NGINX сам обрабатывает передачу файла и копирует файл в буфер перед отправкой. Включение директивы sendfile устраняет этап копирования данных в буфер и разрешает прямое копирование данных из одного дескриптора файла в другой.

Это звучит так, как будто Nginx не использует sendfile по умолчанию.

Однако, как отмечено в этом ответе, файл конфигурации по умолчанию для Nginx явно включает поддержку sendfile для стандартного HTTP-сервера, как показано на https://github.com/nginx/nginx/blob/master/conf/nginx.conf.

person D. Cook    schedule 06.10.2020