
Раздел 9. Разная документация Apache RU EN Пункт 81. Примечания к производительности — настройка Apache Apache 2.x — это веб-сервер общего назначения, обеспечивающий баланс гибкости, переносимости и производительности. Хотя Apache 2.x не разрабатывался специально для установления рекордов производительности, он способен обеспечить высокую производительность во многих реальных ситуациях. По сравнению с Apache 1.3, версия 2.x содержит множество дополнительных оптимизаций для увеличения пропускной способности и масштабируемости. Большинство этих улучшений включены по умолчанию. Однако существуют варианты конфигурации времени компиляции и времени выполнения, которые могут существенно повлиять на производительность. В этом документе описываются параметры, которые администратор сервера может настроить для настройки производительности установки Apache 2.x. Некоторые из этих параметров конфигурации позволяют httpd лучше использовать возможности оборудования и ОС, в то время как другие позволяют администратору обменивать функциональность на скорость. Проблемы с оборудованием и операционной системойЕдинственная самая большая аппаратная проблема, влияющая на производительность веб-сервера, — это оперативная память. Веб-сервер никогда не должен переключаться, поскольку обмен увеличивает задержку каждого запроса сверх точки, которую пользователи считают «достаточно быстрой». Это заставляет пользователей нажимать «Стоп» и «перезагружать», что еще больше увеличивает нагрузку. Вы можете и должны контролировать этот Помимо этого, остальное обыденно: получите достаточно быстрый процессор, достаточно быструю сетевую карту и достаточно быстрые диски, где «достаточно быстрый» — это то, что нужно определить экспериментальным путем. Выбор операционной системы во многом зависит от местных интересов. Но некоторые рекомендации, которые оказались в целом полезными, следующие:
Проблемы с конфигурацией во время выполнения
HostnameLookups и другие аспекты DNSДо Apache 1.3 Рекомендуется выполнять подобную постобработку файлов журнала на каком-либо компьютере, отличном от компьютера с рабочим веб-сервером, чтобы это действие не оказало неблагоприятного влияния на производительность сервера. Если вы используете какие- либо
директивы или (т. е. используете имя хоста или доменное имя, а не IP-адрес), то вы заплатите за два поиска DNS (обратный, за которым следует прямой поиск, чтобы убедиться, что обратный поиск не выполняется). подделка). Поэтому для наилучшей производительности при использовании этих директив используйте IP-адреса, а не имена, если это возможно. Обратите внимание, что можно ограничить директивы, например, внутри Имя хостаПоиск отключен <Файлы ~ "\.(html|cgi)$"> Имя хоста </файлы> Но даже несмотря на это, если вам просто нужны DNS-имена в некоторых CGI, вы можете рассмотреть возможность выполнения вызова FollowSymLinks и SymLinksIfOwnerMatchВезде, где в вашем URL-пространстве у вас нет DocumentRoot "/www/htdocs" <Каталог "/"> Параметры SymLinksIfOwnerMatch </Каталог> и делается запрос на URI DocumentRoot "/www/htdocs" <Каталог "/"> Параметры </Каталог> <Каталог "/www/htdocs"> Опции -FollowSymLinks +SymLinksIfOwnerMatch </Каталог> Это, по крайней мере, позволяет избежать дополнительных проверок пути
АллововеррайдВезде, где в вашем URL-пространстве вы разрешаете переопределения (обычно
DocumentRoot "/www/htdocs" <Каталог "/"> РазрешитьПереопределить все </Каталог> и делается запрос на URI ПереговорыПо возможности избегайте согласования контента, если вы действительно заинтересованы в максимальной производительности. На практике преимущества переговоров перевешивают потери производительности. Есть один случай, когда вы можете ускорить сервер. Вместо использования подстановочного знака, такого как: Индекс DirectoryIndex Используйте полный список опций: DirectoryIndex index.cgi index.pl index.shtml index.html где вы перечисляете наиболее распространенный выбор первым. Также обратите внимание, что явное создание Если вашему сайту требуется согласование содержимого, рассмотрите возможность использования
Отображение памятиВ ситуациях, когда Apache 2.x необходимо просмотреть содержимое доставляемого файла, например, при выполнении обработки включения на стороне сервера, он обычно сопоставляет файл с памятью, если ОС поддерживает какую-либо форму На некоторых платформах это сопоставление памяти повышает производительность. Однако бывают случаи, когда отображение памяти может повредить производительности или даже стабильности httpd:
Для установок, к которым применим любой из этих факторов, следует Отправить файлВ ситуациях, когда Apache 2.x может игнорировать содержимое доставляемого файла, например, при обслуживании статического содержимого файла, он обычно использует поддержку файла отправки ядра для файла, если ОС поддерживает эту операцию На большинстве платформ использование sendfile повышает производительность, устраняя отдельные механизмы чтения и отправки. Однако бывают случаи, когда использование sendfile может повредить стабильности httpd:
Для установок, где применим любой из этих факторов, вы должны Создание процессаДо Apache 1.3 все настройки Правило «одна в секунду» было реализовано, чтобы не загружать машину запуском новых дочерних элементов. Если машина занята созданием потомков, она не может обслуживать запросы. Но он настолько сильно повлиял на воспринимаемую производительность Apache, что его пришлось заменить. Начиная с Apache 1.3, код ослабляет правило «один в секунду». Он создаст одного, подождет секунду, затем породит двух, подождет секунду, затем породит четырех, и так будет продолжаться экспоненциально, пока не будет создаваться 32 ребенка в секунду. Он остановится всякий раз, когда он удовлетворяет
Это кажется достаточно отзывчивым , поэтому почти не нужно крутить ручки С созданием процесса связана смерть процесса, вызванная настройкой
Когда используются проверки активности, дочерние элементы будут заняты, ничего не делая, ожидая новых запросов по уже открытому соединению. Значение секунд по умолчанию Проблемы конфигурации во время компиляцииВыбор MPMApache 2.x поддерживает подключаемые модели параллелизма, называемые многопроцессорными модулями (MPM). При сборке Apache вы должны выбрать MPM для использования. Для некоторых платформ существуют MPM для конкретных платформ:
Дополнительные сведения об этих и других MPM см. в документации по MPM. МодулиПоскольку использование памяти очень важно для производительности, вы должны попытаться исключить модули, которые фактически не используете. Если вы построили модули как DSO, удаление модулей — это просто вопрос комментирования соответствующей Если, с другой стороны, у вас есть модули, статически связанные с бинарным файлом Apache, вам нужно будет перекомпилировать Apache, чтобы удалить ненужные модули. Попутный вопрос, который здесь возникает, конечно же, какие модули вам нужны, а какие нет. Ответ здесь, конечно, будет варьироваться от одного веб-сайта к другому. Однако
минимальный список модулей, с которыми вы можете обойтись, обычно включает Атомные операцииНекоторые модули, такие как По умолчанию APR реализует эти операции, используя наиболее эффективный механизм, доступный на каждой целевой платформе ОС/ЦП. Многие современные ЦП, например, имеют инструкцию, которая аппаратно выполняет операцию атомарного сравнения и замены (CAS). Однако на некоторых платформах APR по умолчанию использует более медленную реализацию атомарного API на основе мьютексов, чтобы обеспечить совместимость со старыми моделями ЦП, в которых такие инструкции отсутствуют. Если вы создаете Apache для одной из этих платформ и планируете работать только на более новых процессорах, вы можете выбрать более быструю атомарную реализацию во время сборки, настроив Apache с помощью параметра Опция
mod_status и ExtendedStatus включеныЕсли вы включите принять сериализацию — несколько сокетовПредупреждение:Этот раздел не был полностью обновлен, чтобы учесть изменения, внесенные в версию 2.x HTTP-сервера Apache. Некоторая информация может быть актуальной, но, пожалуйста, используйте ее с осторожностью. Здесь обсуждается недостаток в API сокетов Unix. Предположим, ваш веб-сервер использует несколько для (;;) {
для (;;) {
fd_set accept_fds;
FD_ZERO (&accept_fds);
for (i = first_socket; i <= last_socket; ++i) {
FD_SET(i, &accept_fds);
}
rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
если (rc < 1) продолжить;
новое_соединение = -1;
for (i = first_socket; i <= last_socket; ++i) {
если (FD_ISSET (i, &accept_fds)) {
новое_соединение = принять (i, NULL, NULL);
если (новое_соединение != -1) разрыв;
}
}
если (новое_соединение != -1) разрыв;
}
process_the (новое_соединение);
}
Но у этой наивной реализации есть серьезная проблема с голоданием. Напомним, что несколько дочерних элементов выполняют этот цикл одновременно, поэтому несколько дочерних элементов будут блокироваться,
Одно из решений — сделать сокеты неблокирующими. В этом случае Другое решение, используемое Apache, заключается в сериализации входа во внутренний цикл. Цикл выглядит так (различия выделены): for (;;) {
accept_mutex_on ();
для (;;) {
fd_set accept_fds;
FD_ZERO (&accept_fds);
for (i = first_socket; i <= last_socket; ++i) {
FD_SET(i, &accept_fds);
}
rc = select (last_socket+1, &accept_fds, NULL, NULL, NULL);
если (rc < 1) продолжить;
новое_соединение = -1;
for (i = first_socket; i <= last_socket; ++i) {
если (FD_ISSET (i, &accept_fds)) {
новое_соединение = принять (i, NULL, NULL);
если (новое_соединение != -1) разрыв;
}
}
если (новое_соединение != -1) разрыв;
}
accept_mutex_off ();
обработать new_connection;
}
Функции
Директиву Другое решение, которое рассматривалось, но так и не было реализовано, состоит в частичной сериализации цикла, то есть впуске определенного количества процессов. Это может представлять интерес только для многопроцессорных систем, где возможно одновременное выполнение нескольких дочерних процессов, а сериализация на самом деле не использует всю пропускную способность. Это возможная область будущих исследований, но приоритет остается низким, поскольку высокопараллельные веб-серверы не являются нормой. В идеале вы должны запускать серверы без нескольких
принять сериализацию — один сокетВышеизложенное прекрасно и модно для серверов с несколькими сокетами, но как насчет серверов с одним сокетом? Теоретически они не должны сталкиваться ни с одной из этих проблем, потому что все дочерние элементы могут просто блокироваться По этой причине мы обнаружили, что многие архитектуры ведут себя более «хорошо», если мы сериализуем даже случай с одним сокетом. Так что это на самом деле значение по умолчанию почти во всех случаях. Грубые эксперименты под Linux (2.0.30 на двухъядерном процессоре Pentium pro 166 с 128 Мб ОЗУ) показали, что сериализация случая с одним сокетом приводит к уменьшению количества запросов в секунду менее чем на 3% по сравнению с несериализованным одиночным сокетом. Но несериализованный односокетный сервер показал дополнительную задержку в 100 мс на каждый запрос. Эта задержка, вероятно, является недостатком на дальних линиях и проблемой только в локальных сетях. Если вы хотите переопределить сериализацию с одним сокетом, вы можете определить
Затяжное закрытиеКак обсуждалось в разделе 8 draft-ietf-http-connection-00.txt, чтобы HTTP-сервер надежно реализовывал протокол, он должен отключать каждое направление связи независимо друг от друга. (Напомним, что соединение TCP является двунаправленным. Каждая половина независима от другой.) Когда эта функция была добавлена в Apache, она вызвала шквал проблем в различных версиях Unix из-за недальновидности. Спецификация TCP не указывает, что Есть два способа сделать это. Одним из них является вариант сокета По большей части Apache реализует это в функции с именем void lingering_close (целое число с)
{
char мусорный_буфер[2048];
/* отключаем передающую сторону */
выключение (с, 1);
сигнал (SIGALRM, lingering_death);
сигнализация (30);
для (;;) {
выберите (s для чтения, 2-секундный тайм-аут);
если (ошибка) перерыв;
если (s готов к чтению) {
если (читать(s,junk_buffer,sizeof(junk_buffer)) <= 0) {
перерыв;
}
/* просто выбросьте все, что здесь есть */
}
}
закрыть (с);
}
Это, естественно, увеличивает некоторые расходы в конце соединения, но это необходимо для надежной реализации. По мере того, как HTTP/1.1 становится все более распространенным, а все соединения являются постоянными, эти расходы будут амортизироваться при увеличении количества запросов. Если вы хотите поиграть с огнем и отключить эту функцию, вы можете определить
Файл таблоРодительский и дочерний элементы Apache общаются друг с другом через так называемую таблицу результатов. В идеале это должно быть реализовано в разделяемой памяти. Для тех операционных систем, к которым у нас либо есть доступ, либо для которых нам предоставлены подробные порты, это обычно реализуется с использованием общей памяти. Остальные по умолчанию используют файл на диске. Файл на диске не только медленный, но и ненадежный (и менее функциональный). Просмотрите
DYNAMIC_MODULE_LIMITЕсли вы не собираетесь использовать динамически загружаемые модули (вероятно, вы этого не сделаете, если читаете это и настраиваете свой сервер для максимальной производительности), вам следует добавить его
Приложение: Подробный анализ трассыВот трассировка системного вызова Apache 2.0.38 с рабочим MPM в Solaris 8. Эта трассировка была собрана с использованием: Опция Другие системы могут иметь другие утилиты отслеживания системных вызовов, такие как В этой трассировке клиент запросил статический файл размером 10 КБ из httpd. Следы нестатических запросов или запросов с согласованием содержимого выглядят совершенно иначе (и в некоторых случаях довольно уродливо). /67: принять(3, 0x00200BEC, 0x00200C0C, 1) (спящий...) /67: принять(3, 0x00200BEC, 0x00200C0C, 1) = 9 В этой трассировке поток прослушивателя выполняется в LWP #67. Обратите внимание на отсутствие accept(2) сериализации. На этой конкретной платформе рабочий MPM по умолчанию использует несериализованный прием, если только он не прослушивает несколько портов.
/65: lwp_park(0x00000000, 0) = 0 /67: lwp_unpark(65, 1) = 0 После принятия соединения поток прослушивателя активирует рабочий поток для обработки запроса. В этой трассировке рабочий поток, обрабатывающий запрос, сопоставляется с LWP #65. /65: получает имясокета(9, 0x00200BA4, 0x00200BC4, 1) = 0 Чтобы реализовать виртуальные хосты, Apache должен знать адрес локального сокета, используемый для принятия соединения. Во многих ситуациях этот вызов можно исключить (например, когда нет виртуальных хостов или когда
/65: брк(0x002170E8) = 0 /65: брк(0x002190E8) = 0 Вызовы /65: fcntl(9, F_GETFL, 0x00000000) = 2 /65: fstat64(9, 0xFAF7B818) = 0 /65:getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0 /65: fstat64(9, 0xFAF7B818) = 0 /65:getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0 /65: setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0 /65: fcntl(9, F_SETFL, 0x00000082) = 0 Затем рабочий поток переводит соединение с клиентом (файловый дескриптор 9) в неблокирующий режим. Вызовы /65: читать(9, "GET/10k.htm".., 8000) = 97 Рабочий поток читает запрос от клиента. /65: стат("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
/65: открыть("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10
Этот httpd был настроен с /65: sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C) = 10269 В этом примере httpd может отправить заголовок ответа HTTP и запрошенный файл с помощью одного /65: запись(4, " 1 2 7 . 0 . 0 . 1 - ".., 78) = 78 Этот /65: выключение(9, 1, 1) = 0 /65: опрос (0xFAF7B980, 1, 2000) = 1 /65: чтение(9, 0xFAF7BC20, 512) = 0 /65: закрыть(9) = 0 Рабочий поток выполняет затяжное закрытие соединения. /65: закрыть(10) = 0 /65: lwp_park(0x00000000, 0) (спящий...) Наконец, рабочий поток закрывает только что доставленный файл и блокирует его до тех пор, пока прослушиватель не назначит ему другое соединение. /67: принять(3, 0x001FEB74, 0x001FEB94, 1) (спящий...) Между тем поток слушателя может принять другое соединение, как только он отправит это соединение рабочему потоку (с учетом некоторой логики управления потоком в рабочем MPM, которая блокирует прослушиватель, если все доступные рабочие потоки заняты). Хотя это не очевидно из этой трассировки, следующая |
![]() |