http://sysoev.ru/mod_accel/
Версия 1.0.24
Модуль mod_accel предназначен для использования Apache в режиме акселератора, то есть, он реализует функциональность ProxyPass модуля mod_proxy. Однако, в отличие от mod_proxy, mod_accel правильно взаимодействует с бэкендом (подробнее об этом ниже), может учитывать при кэшировании cookie, использовать busy lock'и и ограничивать число соединений с бэкендом, позволяет записывать в лог результаты своей работы и, наконец, ответы mod_accel могут быть перекодированы Russian Apache'ем и сжаты модулем mod_deflate.
Модуль mod_accel не может работать в режиме обычного прокси-сервера как mod_proxy. Однако вряд ли целесообразно использовать Apache в этом качестве вместо Squid и Oops. Тем не менее, часто при конфигурировании mod_proxy вместе с функциональностью акселератора по ошибке разрешают страндартное проксирование (ProxyRequests on), что приводит к появлению очередного публичного прокси-сервера. И в то же время, использование Squid или Oops в качестве акселератора менее удобно, чем Apache, поскольку Apache может также обрабатывать обычные непроксируемые запросы.
mod_accel представляет из себя собственно модуль, использующий Apache EAPI, и набор патчей для Apache и модулей mod_proxy, mod_rewrite, mod_ssl и mod_charset (Russian Apache). Кроме того, в дистрибутиве есть три модуля - mod_randban, mod_quoted и mod_freeze, модифицирущие тело передаваемого ответа. Первый изменяет случайное значение в URL'ах для вызова баннеров, второй перекодирует русские символы в конструкциях вида '<a href="/show?%80%81%82">', а третий изменяет некоторые активные теги и параметры.
Дистрибутив необходимо распаковать, перейти в каталог с исходными текстами
и выполнить команду ./configure
,
указав ей путь к исходными текстам Apache и EAPI.
После конфигурирования нужно выполнить команду make
:
Исходные тексты EAPI можно взять из дистрибутива mod_ssl, сам модуль mod_ssl при этом устанавливать не нужно, например:tar zxf mode_accel-1.0.24.tar.gz cd mod_accel-1.0.24 ./configure --with-apache=<apache_dir> --with-eapi=<eapi_dir> make
Если же Apache будет собираться с использованием модуля mod_ssl, то параметр./configure --with-apache=../apache_1.3.20 --with-eapi=../mode_ssl-2.8.4-1.3.20/pkg.eapi
--with-eapi
не нужен,
поскольку mod_ssl сам устанавливает Apache EAPI.
При использании модулей mod_charset или mod_ssl их необходимо установить до mod_accel, поскольку при установке mod_accel эти модули необходимо патчить. mod_ssl рекомендуется устанавливать так, как описано в разделе "The flexible APACI-only way [FOR REAL HACKERS]" файла INSTALL из дистрибутива mod_ssl.
При конфигурировании можно указать ещё несколько параметров:
--with-mod_randban
- установить исходный текст
модуля mod_randban в каталог
<apache_dir>/src/modules/extra/
;
--with-mod_quoted
- установить исходный текст
модуля mod_quoted в каталог
<apache_dir>/src/modules/extra/
;
--with-mod_freeze
- установить исходный текст
модуля mod_freeze в каталог
<apache_dir>/src/modules/extra/
;
--without-mod_rewrite
- не патчить модуль mod_rewrite;
--without-cachemgr
- не собирать cachemgr.
Параметр появился в версии 1.0.2;
--with-patch=<path_to_patch>
-
использовать указанную программу patch
.
Параметр появился в версии 1.0.7.
Начиная с версии 1.0.7, параметры --without-mod_charset
и --without-mod_ssl
не поддерживаются.
Команда make
накладывает патчи на исходные тексты Apache
и модулей mod_proxy, mod_rewrite, mod_charset и mod_ssl,
устанавливает при необходимости Apache EAPI
и копирует исходные тексты модуля mod_accel в каталог
<apache_dir>/src/modules/accel/
.
Кроме того, если указаны дополнительные модули mod_randban,
mod_quoted или mod_freeze то они копируются в каталог
<apache_dir>/src/modules/extra/
.
Если предполагается использовать busy lock'и и ограничение числа соединений и ждущих процессов, то нужно также установить библиотеку mm (она доступна по адресу http://www.engelschall.com/sw/mm/):
С параметромtar zxf mm-1.2.1.tar.gz cd mm-1.2.1 ./configure --disable-shared make
--disable-shared
библиотека будет
собрана статически.
Библиотеку можно собрать динамически, но в этом случае после сборки
её нужно установить командой make install
.
При конфигурировании Apache необходимо активировать модули, EAPI и EAPI_MM (если используется библиотека mm):
До версии mod_accel 1.0.7 модуль mod_accel должен быть указан после модулей mod_quoted и mod_randban. Начиная с версии 1.0.7, порядок не имеет значения. В случае, если библиотека mm собрана динамически, переменнаяcd <apache_dir> EAPI_MM=<mm_dir> ./configure ... --enable-rule=EAPI --activate-module=src/modules/extra/mod_randban.o --activate-module=src/modules/extra/mod_quoted.o --activate-module=src/modules/extra/mod_freeze.o --activate-module=src/modules/accel/libaccel.a ...
EAPI_MM
будет выглядеть таким образом:
EAPI_MM=SYSTEM
После установки Apache необходимо сделать каталог, в котором будут создаваться файлы кэша и временные файлы. Пользователь, от имени которого работают процессы Apache, должны иметь права на чтение и запись в этот каталог. Этот каталог нужно указать в директиве AccelCacheRoot, например:
AccelCacheRoot cache
Модуль mod_accel может подгружаться динамически. Начиная с версии 1.0.7, порядок загрузки не имеет значения.
До версии 1.0.7, как и при статической сборке, модуль mod_accel должен быть указан после модулей mod_quoted и mod_randban:
Если модуль mod_ssl тоже загружается динамически, то он должен быть указан до модуля mod_accel (это также не имеет значения, начиная с версии 1.0.7):LoadModule randban_module modules/mod_randban.so LoadModule quoted_module modules/mod_quoted.so LoadModule accel_module modules/libaccel.so
LoadModule ssl_module modules/libssl.so LoadModule accel_module modules/libaccel.so
В фазе трансляции URI mod_accel проверяет, не совпадает ли начало URI c каким-либо из префиксом, указанных в списке директив AccelPass. Если совпадение найдено, то просматривается список директив AccelNoPass. Если в этом списке не найден ни один префикс или регулярное выражение, соответствующие URI, то обработчиком этого запроса будет "accel-handler", который направит этот запрос на другой сервер. Например, запрос "http://frontend/test/one.cgi?test=1" директива
преобразует в запрос "http://backend/test/one.cgi?test=1".AccelPass /test/ http://backend/test/
Если ответ на запрос может быть закэширован, то проверяется его наличие в кэше. Ключём для поиска в кэше является результат хеш-функции md5, в качестве аргумента которой передаётся преобразованный URL, в нашем случае "http://backend/test/one.cgi?test=1". Если ответ найден в кэше, то он считывается блоками, размер которых задаётся директивой AccelCacheSendSize и отдаётся клиенту.
Если же ответа нет, или он устарел, или же ответ вообще некэшируемый, то запрос должен быть передан бэкенду. После этого проверяются busy lock'и, число соединений с бэкендом и число ждущих процессов. Затем, если у запроса есть тело (например, запрос вида POST), то оно считывается в буфер, размер которого задаётся директивой AccelRequestBuffSize. Если тело запроса превышает размер буфера, то оно сохраняется во временный файл. И только после этого mod_accel соединяется с бэкендом (или с одним из них), передаёт ему запрос и затем читает заголовок ответа. Сокеты бэкенда и клиента переводятся в неблокирующий режим и клиенту передаётся заголовок ответа. После этого читается тело ответа в буфер приёма ответа, размер которого задаётся директивой AccelBkRcvBuffSize. Как только размер считанного становится равным размеру этого буфера, создаётся временный файл и в него записывается содержимое буфера. По мере получения ответа он отдаётся клиенту блоками размером, заданным директивой AccelSendSize.
В процессе передачи ответа клиенту он может модифицироваться цепочкой модулей, например, модулями mod_randban, mod_quoted и mod_freeze.
Как только ответ от бэкенда получен полностью, сокет бэкенда закрывается, а сокет клиента переводится в блокирующий режим. После этого ответ может быть записан в кэш и может использоваться другими процессами Apache.
Прежде чем запрос будет передан бэкенду, проверяется наличие ответа в кэше. Это происходит в следующем порядке:
Если активна директива AccelNoCache или запрос не вида GET или HEAD, то он передаётся бэкенду и заметка "accel_st" будет равна "PASS".
Если установлена заметка "accel_nocache", то запрос передаётся бэкенду и заметка "accel_st" будет равна "NTNC".
После этого проверяется заголовок "Authorization". Если директивы AccelIgnoreAuth и AccelRevalidateUser не активны, то запрос с авторизацией всегда передаётся бэкенду. На этом этапе заметка "accel_st" равна "AUTH".
Если предыдущие проверки пройдены, то считается, что ответ на запрос в принципе может быть закэширован.
Далее, если директива AccelInvalidate активна, то проверяется наличие строки обновления в конце URL'а. Если она есть, запрос передаётся бэкенду и заметка "accel_st" будет равна "INVL".
Если директива AccelIgnoreNoCache не активна,
то проверяются заголовки
Затем ответ ищется в кэше. Если он не найден, то проверки busy lock'ов, числа соединений с бэкендом и числа ждущих процессов. Если ответ не обрабатывается другим процессом, число соединений и ждущих процессов не достигло максимума, то запрос передаётся бэкенду и заметка "accel_st" будет равна "MISS".
Если ответ есть и директива AccelIgnoreNoCache не активна,
то проверяется заголовок
Если директива AccelRevalidateUser активна, то запрос передаётся бэкенду и заметка "accel_st" будет равна "RVUS".
После этого проверяется, не устарел ли ответ. Если устарел, то после проверки busy lock'ов, числа соединений с бэкендом и числа ждущих процессов запрос передаётся бэкенду и заметка "accel_st" будет равна "EXPR".
И наконец, если ответ не устарел или же соединение с бэкендом запрещено, то он возвращается клиенту и заметка "accel_st" будет равна "HIT".
Если ответ на запрос есть в кэше, но уже устарел, то в запрос
к бэкенду добавляется заголовок
Если ответ на запрос клиента может быть не полным, например,
если в запросе клиента есть заголовки
То же самое относится к запросу HEAD. Если ответа в кэше нет, но он в принципе кэшируем, то к бэкенду делается запрос GET, чтобы опять же получить полный ответ и, возможно, сохранить его в кэше. Клиенту же возвращается только заголовок ответа.
Прежде чем запрос уходит к бэкенду, предварительно проверяются busy lock'и, число соединений с бэкендом и число ждущих процессов. Busy lock позволяет не передавать бэкенду кэшируемый запрос в том случае, если точно такой же запрос уже обрабатывается бэкендом. Busy lock устанавливается директивой AccelBusyLock и гарантирует, что в течение заданного времени от начала выполнения запроса к бэкенду только один из процессов Apache передаст этот запрос бэкенду. Если в кэше есть устаревший ответ на этот запрос, но он устарел не более чем на время, заданное директивой AccelMaxStale, то все остальные процессы будут возвращать этот устаревший ответ из кэша. В противном случае все остальные процессы, выполняющие такой же запрос, будут или ждать ответ, который получит первый процесс, или же ждать истечения busy lock'а, установленного этим процессом. AccelBusyLock позволяет установить три значения busy lock'а. Первый используется в случае, если ответа в кеше нет или он устарел более чем на время, заданное директивой AccelMaxStale. Второй используется в случае, если ответ в кэше устарел менее чем на время, заданное предыдущей директивой. Второе значение рекомендуется устанавливать больше, чем первое. Третий задаёт максимальное время, которое процесс может провести в busy lock'е, поскольку процесс может ждать последовательно освобождения нескольких busy lock'ов. Предположим, что пришли одновременно три одинаковых запроса и у на заданы такие параметры:
Первый запрос будет передан бэкенду. Два других ждут в busy lock'е. Предположим, что по истечении 20 секунд ответ от бэкенда не получен. Второй запрос передаётся бэкенду, третий же продолжает ждать первые два ответа. Но максимальное суммарное время его ожидания не может быть более 30 секунд, поэтому если в течение этого времени бэкенд не ответит, то третий запрос будет передан бэкенду при условии, что число соединений с бэкендом не достигло максимума.AccelBusyLock 20 25 30
Допустим, у нас заданы такие параметры:
Проиллюстрируем логику работы busy lock'ов следующим примером:AccelBusyLock 10 15 AccelMaxStale 60
00:00. Пришёл запрос, ответа на который нет в кэше. Поскольку в данный момент никто не обрабатывает такой же запрос, то процесс передаёт запрос бэкенду, предварительно установив busy lock, который истечёт в 00:10 (первое значение AccelBusyLock равно 10 секундам).
00:04. Пришёл второй запрос. Поскольку первый ещё обрабатывается, то процесс, принявший второй запрос, ждёт освобождения busy lock'а или появления ответа в кэше.
00:07. Пришёл третий запрос. Поскольку первый всё ещё обрабатывается, то процесс, принявший третий запрос, ждёт освобождения busy lock'а или появления ответа в кэше так же, как и второй процесс.
00:10. Поскольку busy lock первого процесса истёк, один из процессов, допустим, третий устанавливает ещё один busy lock и передаёт запрос бэкенду. Второй процесс, как и прежде, ждёт освобождения уже нового busy lock'а или появления ответа в кэше. Необходимо заметить, что по истечении busy lock'а только один процесс из ждущих может установить ещё один busy lock.
00:12. Первый процесс получил ответ и записал его в кэш.
Заметка "accel" для этого запроса будет равна
00:23. Третий процесс получил ответ и обновил ответ в кэше.
Заметка "accel" будет равна
03:10. Пришёл четвёртый запрос. Поскольку ответ ещё не устарел,
то он отдаётся из кэша.
Заметка "accel" будет равна
06:16. Пришёл пятый запрос. Поскольку запрос устарел в 05:23 и в данный момент никто не обрабатывает такой же запрос, то процесс передаёт запрос бэкенду, предварительно установив busy lock.
06:20. Пришёл шестой запрос. Ответ на него уже устарел,
но ещё не очень старый (AccelMaxStale равен
06:24. Пришёл седьмой запрос. Ответ на него уже совсем устарел, но поскольку такой же запрос обрабатывается и его busy lock для седьмого запроса истечёт в 06:26 (для ответов устаревших больше, чем на время, заданное директивой AccelMaxStale, используется первое значение AccelBusyLock, в нашем случае равное 10 секундам), то процесс ждёт освобождения busy lock'а или появления ответа в кэше.
06:25. Процесс, работающий с пятым запросом, получил ответ от бэкенда
и обновил его в кэше.
Заметка "accel" будет равна
Busy lock'и предназначены для уменьшения нагрузки на бэкенд.
В тоже время возможны ситуации, когда бэкенд не справляется
со обработкой полученных запросов, а новые запросы продолжают поступать.
В этом случае процессы фронтенда, обрабатывающие новые запросы,
будут или ждать ответа от бэкенда, подсоединившись к нему,
или пытаться соединиться с бэкендом, или же ждать в busy lock'е.
Число процессов фронтенда при этом может достигнуть своего максимума
и если фронтенд кроме проксирования этого бэкенда должен заниматься
ещё и другими запросами, то эти запросы не будут обслуживаться.
Таким образом, один перегруженный бэкенд может сделать недоступными
остальные ресурсы, обслуживаемые его фронтендом.
Для избежания подобных ситуаций в директиве
AccelPass можно указать флаги
MC и MW, позволяющие ограничить
соответственно число соединений с бэкендом и число процессов,
ждущих этот бэкенд в busy lock'е.
Если достигнут максимум по одному из параметров и в кэше есть ответ на запрос,
то он всегда возращается клиенту, независимо от того, насколько он устарел.
Если же ответа в кэше нет, то возвращается ошибка
--without-mod_rewrite
.
Примитивное распределение нагрузки и отказоустойчивость можно
реализовать на основе DNS, когда одно имя соответствует нескольким IP-адресам.
Необходимо заметить, что указание альтернативных адресов
в файле /etc/hosts
для этого не подойдёт -
нужно делать запросы к DNS-серверу.
Кроме того, необходимо указать флаг NR в директиве
AccelPass для запрещения определения IP-адреса
бэкенда на старте.
В этом случае фронтенд будет определять IP-адреса бэкендов при каждом обращении
и соединяться с одним из нескольких бэкендов.
Для генерации ключа в кэше используется URL в том виде, в каком он
получается после замены локального префикса на проксируемый без
определения IP-адресов, поэтому с точки зрения mod_accel ответы
от разных бэкендов на один и тот же запрос равнозначны и попавший
в кэш ответ одного сервера будет отдаваться клиентам до тех пор, пока
не устареет.
То же самое относится к busy lock'ам и ограничениям на соединения,
то есть, группа бэкендов рассматривается как один бэкенд.
Примитивную отказоустойчивость можно реализовать, задав небольшое значение второму параметру директивы AccelTimeout. По умолчанию таймаут на соединение равен примерно 75 секундам. При нормальной работе соединение, как правило, устанавливается за доли секунды. Если установить этот таймаут на несколько секунд, то по его истечении mod_accel попытается подсоединиться к следующему бэкенду. Однако не всегда бэкенд может вернуть результат, даже если фронтенд смог с ним соединиться. Поэтому по истечении таймаутов, заданных параметрами директивы AccelTimeout, при обрыве соединения с бэкендом или при получении ответа с результатом 5XX mod_accel закрывает соединение и переходит к следующему бэкенду. С помощью директивы AccelRetry5XX off можно запретить пытаться соединиться с другим бэкендом при получении ответа с результатом 5XX. Результаты попыток соединений фиксируются в заметках, то есть, их можно увидеть в логе, но они никак не используются для выбора бэкенда при следующих запросах.
Решение от том, кэшировать полученный ответ или нет, принимается в следующем порядке:
Прежде всего, заметка "accel_st" не должна быть равна "PASS", "NTNC" и "AUTH".
Кроме того, ответ от бэкенда должен быть получен полностью
и иметь код
Если заметка "accel_st" равна "NTNC", то заметка "accel_bc" будет равна "NNC". Полученный ответ не кэшируется, но и старый ответ в кэше не удаляется.
Затем проверяется специальный заголовок
Если предыдущий заголовок отсутствует, то проверяется заголовок
Затем проверяется заголовок "Expires". В случае, если время, указанное в заголовке "Date", меньше либо равно времени, указанного в заголовке "Expires", ответ не кэшируется. Проверку этого заголовка можно запретить с помощью директивы AccelIgnoreExpires on. Если решение о кэшировании принято на основании этого заголовка, то заметка "accel_bc" будет равна "EXP", а заметка "accel_bct" - разнице во времени, указанного в заголовке "Expires" и "Date".
Если предыдущие проверки ни к чему не привели и код ответа равен
Если указана директива AccelLastModifiedFactor,
а в ответе есть заголовок
Expires = (Date - LastModified) * AccelLastModifiedFactor / 100
Время устаревания отсчитывается от текущего времени на фронтенде. Если решение о кэшировании принято на этом этапе, то заметка "accel_bc" будет равна "LMF", а заметка "accel_bct" - вычисленному времени.
Наконец, время устаревания можно указать директивой AccelDefaultExpire, отсчитываемое от текущего времени на фронтенде. В этом случае заметка "accel_bc" будет равна "ADE", а заметка "accel_bct" - указанному времени.
Если в результате не удалось определить время устаревания, то ответ не кэшируется и заметки "accel_bc" и "accel_bct" будут равны "-".
Начиная с версии 1.0.2, поведением модуля mod_accel можно управлять с помощью заметки "accel_nocache". Если выставить эту заметку, то mod_accel всегда будет делать запрос к бэкенду, не проверяя кэш. Полученный ответ никогда не кэшируется, а если в кэше ответ уже есть, то он не удаляется. Начиная с версии 1.0.24, то же самое, можно делать с помощью переменной среды "ACCEL_NOCACHE".
Начиная с версии 1.0.18, модулю mod_accel в заметке "accel_request_body" можно передавать тело запроса.
Начиная с версии 1.0.18, модулю mod_accel в заметке "accel_rewrite_response" можно передавать адрес процедуры для обработки ответа бэкенда. Процедура должна иметь следующий прототип:
Она вызывается после получения заголовка и, возможно, первой части ответа от бэкенда. Если ответ бэкенда нужно вернуть неизменным, то процедура должна вернуть значение DECLINED и mod_accel продолжит обработку запроса. При возврате любого другого значения предполагается, что процедура сама полностью обработала запрос.int rewrite_handler(accel_rec *a);
Если ответы могут быть закэшированы, то заголовок "Cookie" удаляется из запроса к бэкенду, а заголовок "Set-Cookie" - из ответа бэкенда, поскольку cookie может влиять на содержимое ответа. Однако, если Вы уверены, что cookie никак не влияют на содержимое ответов, то можете установить директиву AccelPassCookie on. Если Вы уверены, что заголовок "Set-Cookie" имеет смысл кэшировать, то можете установить директиву AccelCacheSetCookie on. Кроме того, можно кэшировать ответ в зависимости от cookie с помощью директивы AccelCacheCookie. Наконец, если авторизация сделана с помощью cookie, то можно использовать директиву AccelRevalidateUser.
Деятельность mod_accel можно анализировать с помощью заметок, которые можно записывать в лог в виде %{accel}x:
accel_r первая строка запроса, переданного бэкенду, например,
accel заметка, в которой объединены все нижеперечисленные заметки,
её формат такой:
accel_st состояние запроса. Может принимать значения "PASS", "NTNC", "AUTH", "INVL", "PGNC", "MISS", "AGED", "EXPR", "RVUS" и "HIT" в порядке, описанном в разделе Когда ответ может быть получен из кэша и значение "RMVD", если файл был удалён из кэша с помощью менеджера кэша.
accel_et время в секундах, показывающее насколько устарел хранящийся в кэше ответ на запрос.
accel_lt время в секундах, в течение которого процесс был в busy lock'е.
accel_ls состояние busy lock'а, ограничений на момент отдачи ответа
на запрос и показатель свежести ответа.
Может быть комбинацией таких значений - "U", "C", "W" и "N".
Символ "U" означает, что запрос уже обновляется другим процессом.
Это значение всегда появляется в сочетании с заметкой accel_st,
равной "HIT", например,
accel_bs код ответа бэкенда, если же ответ был получен из кэша, то эта заметка будет равна "HIT".
accel_bc на основании чего было принято решение о кэшировании ответа. Может принимать значения - "NNC", "XAE", "CTL", "EXP", "MVD", "LMF" и "ADE" в порядке, описанном в разделе Какие ответы кэшируются.
accel_bct время кэширования в секундах.
accel_bt время обработки запроса бэкендом в секундах.
accel_bnr - количество операций чтения ответа бкэенда. Может быть на единицу больше реального числа, в частности для маленьких ответов, размер которых меньше кадра ethernet'а реальное количество чтений будет 2 (весь ответ принимается за одно чтение, при втором чтении будет получен конец файла), а в заметке будет записано 3. Тем не менее, эта заметка отражает реальное положение вещей в случае большого ответа и некоторой задержки, заданной в директиве AccelWaitBeforeBodyRead.
accel_bfr - суммарный размер заголовка ответа и части тела ответа, полученной за первое чтение после задержки, заданной в директиве AccelWaitBeforeBodyRead.
accel_br - полный размер ответа, полученный от бэкенда в байтах. Включает в себя заголовок ответа.
accel_fl - флаги ответа. Может быть комбинацией значений "R", "Q" и "F". "R" указывает, что ответ был обработан модулем mod_randban, "Q" - модулем mod_quoted, а "F" - модулем mod_freeze.
Чистка кэша делается отдельным процессом - сборщиком мусора,
который запускается основным сервером Apache и им же контролируется.
После старта сборщик мусора переключается на пользователя и группу,
указанных в директивах User и Group.
Большую часть времени этот процесс спит, просыпаясь лишь для чистки кэша.
Его можно отличить от других процессов Apache с помощью команды
ps
- в имени процесса присутствует
строка "garbage collector".
Директива AccelClean задаёт, как часто нужно чистить кэш.
Чистить можно раз в сутки в заданное время или же через определённый
интервал времени, который отсчитывается от времени запуска процесса
или от времени завершения последней чистки кэша.
Необходимо отметить, что при старте сборщик не сразу начинает
чистку кэша, а ждёт одну минуту, поскольку, как правило, во время
перезапуска Apache нагрузка на сервер увеличивается.
Кроме того, во время чистки сборщик засыпает на одну секунду после
проверки каждой 1000 файлов. Под файлами в данном случае подразумеваются
не только обычные файлы кэша, но файлы каталогов, потому что
при задании уровней кэша kill
и Apache
перезапустит сборщика снова.
Сборщик удаляет файлы в кэше, которые устарели более часа назад или же к ним не обращались в течение времени, заданного директивой AccelCleanLastAccessed и не следит за размером кэша, поскольку это имеет смысл в случае проксирования Интернета, а не конкретного сайта, размер которого более или менее известен. Кроме того, сборщик удаляет временные файлы, к которым не обращались более часа и каталоги и файлы кэша, оставшиеся после изменения структуры кэша.
Директива определяет, добавлять или нет в заголовок "Via" в запросе,
передаваемом бэкенду, строку о фронтенде.
Добавляемая строка имеет следующий вид -
Директива определяет, добавлять или нет в заголовок "X-Forwarded-For" в запросе, передаваемом бэкенду, IP-адрес, с которого был сделан запрос к фронтенду.
Директива задаёт размер буфера в килобайтах для приёма ответа от бэкенда. Если размер ответа превышает размер буфера, то содержимое буфера записывается во временный файл.
Директива задаёт размер TCP-буфера ядра в килобайтах для приёма ответа от бэкенда. Размер устанавливается системным вызовом setsockopt() с параметром SO_RCVBUF. Если значение директивы равно нулю, то setsockopt() не вызывается и используется размер TCP-буфера, заданный по умолчанию.
Директива задаёт три значения busy lock'ов.
Первый используется в случае, если ответа в кеше нет или он
устарел более чем на время, заданное директивой
AccelMaxStale.
Второй используется в случае, если ответ в кэше устарел
менее чем на время, заданное предыдущей директивой.
Третий задаёт максимальное время ожидания в busy lock'е.
Подробно логика работы busy lock'ов описана в разделе
Busy lock'и.
Оба параметра можно задавать в виде строки, например,
Если второй параметр не задан, то он равен первому.
Если третий параметр не задан, то он равен первому параметру директивы AccelTimeout. Третий параметр появился в mod_accel, начиная с версии 1.0.7. В более ранних версиях его значение равно первому параметру директивы AccelTimeout.
Директива задаёт имена cookie, которое будет учитываться при кэшировании ответа сервера. При задании имени cookie можно использовать имя или регулярное выражение. Символы "~*" позволяют задать регулярное выражение без учёта регистра символов. Параметр "all" задаёт все cookie. Символ "!" позволяет исключить часть cookie. Параметр "off" запрещает учёт cookie при кэшировании. Предположим, у нас заданы директивы
В этом случае запрос "http://frontend/test/one.html" будет перенаправлен в запрос "http://backend/test/one.html". Ключём для поиска в кэше является результат хеш-функции md5, в качестве аргумента которой передаётся преобразованный URL, в нашем случае "http://backend/test/one.cgi?test=1". Однако, если пользователь передал cookie, например, "userid=12345; pref=34; id=92", то аргументом хеш-функции md5 будет строкаAccelPass /test/ http://backend/test/ AccelCacheCookie all !~^id
Директива учитывает только заголовки "Cookie", приходящие от клиента, и никак не влияет на заголовок "Set-Cookie", переданный от бэкенда.
В одном блоке может быть задано несколько директив AccelCacheCookie. Если в блоке не указана ни одна директива, то они наследуются из предыдущего. Директивы, заданные в вложенном блоке не объединяются с директивами, задаными в предыдущем блоке. Параметр "off" отменяет действие всех остальных параметров.
В версии 1.0.2 допустимы только два вида параметров - "off" и строка. Кроме того, в одной директиве можно указывать только один параметр и имена cookie не сортируются.
Директива задаёт каталог, в котором будут создаваться файлы кэша
и временные файлы. Весь кэш должен находиться на одном
дисковом разделе, так как временные файлы перемещаются в кэш
операцией create_cache
и запретить автоматическое создание каталогов.
Например, директива
указывает, что кеш находится в каталогеAccelCacheRoot /var/cache 1 1 noauto
/var/cache
,
глубина его вложености 2, имена каталогов обоих уровней - Директива определяет размер буфера в килобайтах для передачи ответа из кэша клиенту.
Директива определяет, можно ли сохранять в кэш заголовок "Set-Cookie".
Директива задаёт время или интервал чистки кэша. Если в строке указан символ "@", то чистка делается раз в сутки в указанное время, иначе значение означает интервал времени, по истечении которого производится чистка кэша. Примеры использования:
AccelClean "1 hour 30 minutes" AccelClean "@ 5 hours"
Директива определяет максимальное время неактивной жизни файла в кэше. Если в течение этого времени к файлу не обращались, то файл будет удалён при чистке кэша, даже если он не считается устаревшим.
Директива задаёт размер буфера, используемого модулями, модифицирующими тело ответа.
Начиная с версии 1.0.11, размер буфера настраивается автоматически и директива упразднена.
Директива задаёт время хранения ответа при условии, что определить это время другими способами не удалось.
Директива определяет, игнорировать или нет заголовок "Authorization"
в запросе клиента.
Директиву можно применять в случае, если авторизация проводится
фронтендом и ответ бэкенда не зависит от пользователя и следовательно
может выдаваться из кэша.
Кроме того, некоторые программы пакетного скачивания, в частности FlashGet,
используют заголовок "Authorization" в роли заголовка
Директива определяет, игнорировать или нет заголовки "Expires" и "Cache-Control", выдаваемые бэкендом.
Директива определяет, игнорировать или нет заголовки
При нажатии на Reload Netscape посылает заголовок
Netscape 6 и Mozilla при нажатии на Reload посылает два заголовка
При нажатии на Refresh MSIE под Windows до версии 5.5 включительно
посылает заголовок
При нажатии на Reload Konqueror посылает заголовки
Заголовок
Директива задаёт строку, при нахождении которой в конце URL содержимое кэша для данного запроса будет обновленно. Например, если задана директива
то для обновления запроса "http://frontend/test/one.hml?arg=1", нужно сделать запрос "http://frontend/test/one.hml?arg=1_INVALIDATE".AccelInvalidate _INVALIDATE
Директива задаёт число в процентах для определения времени кэширования на основании текущего времени и заголовка "Last-Modified". Подробно это описано в разделе Какие ответы кэшируются.
Директива задаёт время, в течение которого устаревший ответ на запрос
может отдаваться из кэша при условии, что один из процессов
Apache уже получает обновлённый ответ от бэкенда.
Оба параметра можно задавать в виде строки, например,
Директива указывает, могут ли ответы на запросы кэшироваться.
Эта директива определяет, какие запросы не должны передаваться на другой сервер, даже если префикс запроса совпадает с одним из префиксов, указанных в директиве AccelPass. Это может быть полезно в случае, когда сайт от корня создаётся бэкендом, но статические файлы лучше отдавать фронтендом. Например, если заданы такие директивы
то запросы, начинающиеся на "/images/" или "/download/", не будут передаваться бэкенду. Кроме того, запросы заканчивающиеся на ".jpg" или ".JPG" также не будут передаваться бэкенду. Символы "~*" перед регулярным выражением указывают игнорирование регистра. Необходимо заметить, что регулярные выражения применяются только к URI, и не применяются к PATH_INFO и аргументам запроса.AccelPass / http://backend/ AccelNoPass /images/ /download/ ~*\.jpg$
В одном блоке может быть задано несколько директив. Директивы, заданные в вложенном блоке объединяются с директивами, задаными в предыдущем блоке.
В mod_accel до версии 1.0.3 нельзя использовать регулярные выражения с игнорированием регистра. Кроме того, в директиве можно использовать только один параметр и между регулярным выражением и символом "~" может стоять пробел.
Директива определяет, какие запросы должны передаваться на другой сервер. Например, директива
будет перенаправлять все запросы, начинающиеся на /test/, в запросы "http://backend/test/". Например, запрос "http://frontend/test/one.html" будет перенаправлен в запрос "http://backend/test/one.html".AccelPass /test/ http://backend/test/
Если не установлен флаг PH, то в запрос всегда включается заголовок "Host", содержащий имя и порт (если порт не равен 80) сервера, на который перенаправлен запрос.
Если ответ на запрос представляет из себя редирект, то заголовок "Location" при необходимости корректируется, то есть, если заголовок "Location" содержит "http://backend/test/two.html", то он будет изменён на "http://frontend/test/two.html". В этом смысле директива
эквивалента двум директивам модуля mod_proxyAccelPass /test/ http://backend/test/
Кроме заголовкa "Location" также корректируется заголовок "Refresh".ProxyPass /test/ http://backend/test/ ProxyPassReverse /test/ http://backend/test/
Начиная с версии 1.0.11, в ответ на запрос /test mod_accel возвращает редирект на URL с добавленным слэшом, то есть, http://frontend/test/.
Директивы просматриваются в порядке их описания, поэтому более общие перфиксы нужно раполагать в конце, например:
AccelPass /test/ http://backend1/test/ AccelPass / http://backend2/
В директиве можно использовать следующие флаги:
MC=<число> - Maximum Connect;
MW=<число> - Maximum Waiting;
MP=<H|P|L|Tтэг> - Maximum Part.
Флаг MP=Tтэг появился в mod_accel 1.0.6.
Эти флаги ограничивают число соединений с бэкендом (MC) и число процессов ждущих в busy lock'ах (MW). Если флаг MW не указан, то он будет равен значению флага MC. Флаг MP определяет, какая часть URL во втором параметре директивы используется для ограничения. MP=L означает весь URL, указанный в директиве, MP=P - имя бэкенда и порт и MP=H - только имя бэкенда. Последний вариант используется по умолчанию. Кроме того, флаг MP=Tтэг позволяет гибко настривать ограничение. В качестве тэга может быть выбрано любое слово. Расмотрим действие флагов на примере:
Первые две директивы ограничивают число соединений с портом 80 сервера backend до 30 и число процессов, ждущих в busy lock'ах до 40. Однако это не относится к URL, начинающимся на "http://backend:80/t5/" - для них число соединений и ждущих процессов ограничено 10. То же самое относится к URL, начинающимся на "http://backend:80/t6/" и "http://backend:80/t7/" - для них суммарное число соединений и ждущих процессов ограничено 15. Таким образом, максимальное суммарное число соединений с портом 80 сервера backend - 55 (30, 10 и 15), число ждущих процессов - 65 (40, 10 и 15). В то же время число соединений с портами 8080 и 8081 сервера backend в сумме не может превысить 20, а число ждущих процессов - 30. Всего же с сервером backend может быть установленно не более 75 (30, 10, 15 и 20) соединений, а число ждущих при этом процессов - не более 95 (40, 10, 15 и 30).AccelPass /t1/ http://backend:80/t1/ [MC=30,MW=40,MP=P] AccelPass /t2/ http://backend:80/t2/ [MC=30,MW=40,MP=P] AccelPass /t3/ http://backend:8080/t3/ [MC=20,MW=30,MP=H] AccelPass /t4/ http://backend:8081/t4/ [MC=20,MW=30,MP=H] AccelPass /t5/ http://backend:80/t5/ [MC=10,MW=10,MP=L] AccelPass /t6/ http://backend:80/t6/ [MC=15,MW=15,MP=Tbk] AccelPass /t7/ http://backend:80/t7/ [MC=15,MW=15,MP=Tbk]
В директивах, ограничивающих доступ к одному и тому же ресурсу, следует использовать одинаковые значения флагов MC и MW. То есть, директивы
работать будут, но, возможно, не так, как Вы ожидаете.AccelPass /t3/ http://backend:8080/t3/ [MC=10,MW=20,MP=H] AccelPass /t4/ http://backend:8081/t4/ [MC=20,MW=30,MP=H]
Максимальное время, в течение которого процесс считается соединённым с сервером или ждущим его, равно 1 часу. Это ограничение необходимо для ситуации, если процесс аварийно завершился и не успел изменить свое состояние.
NR - No Resolve.
На старте mod_accel определяет один ip-адрес каждого бэкенда и в дальнейшем использует только его. Флаг NR запрещает определение ip-адресов на старте. Этот флаг нужно использовать, когда одному доменному имени соответствует несколько бэкендов и с помощью сервера DNS реализуется примитивное распределение нагрузки и отказоустойчивость.
PH - Preserve Host.
Этот флаг появился в mod_accel 1.0.12.
Флаг PH позволяет передать бэкенду имя хоста в заголовке "Host" неизменным. Если в запросе клиента этот заголовок отсутствует, то он также не передаётся бэкенду. Номер порта при необходимости изменяется. Если вместе с флагом PH заданы флаги MC или MW, но не задан флаг MP, то для ограничения числа соединений или ждущих процессов используется содержимое заголовка "Host". При формировании ключа в кэше используется заголовок "Host".
Флаг MP вместе с PH работает корректно, начиная с версии 1.0.20.
Если фронтенд и бэкенд используют разные порты, то mod_accel 1.0.12 не корректирует порт в заголовках "Location" и "Refresh". Начиная с версии 1.0.13, mod_accel корректно работает с этими заголовками.
Начиная с версии 1.0.14, mod_accel сначала проверяет директивы AccelPass из виртуального сервера, а лишь затем директивы из основного сервера. Такой порядок позволяет задать в основном сервере директиву с флагом PH, а затем переопределить её в некоторых виртуальных серверах.
Начиная с версии 1.0.16, mod_accel позволяет использовать в директиве AccelPass специальное имя хоста _the_same_host_, например:
В этом случае mod_accel в качестве IP-адреса бэкенда будет использовать тот же IP-адрес, что и у фронтэнда. Необходимо заметить, что при использовании этого имени хоста автоматически устанавливается флаг PH. Если вместе с именем _the_same_host_ заданы флаги MC или MW, но не задан флаг MP, то для ограничения числа соединений или ждущих процессов используется ip-адрес хоста. При формировании ключа в кэше используется IP-адрес бэкенда.AccelPass / http://_the_same_host_:8080/
Флаг MP вместе с _the_same_host_ работает корректно, начиная с версии 1.0.20.
Директива определяет, можно ли передавать cookie клиента бэкенду, если его ответ на запрос в принципе может быть закэширован. Поскольку ответы на запросы с одинаковым URL могут отличаться в зависимости от содержимого cookie, то такие ответы кэшировать нельзя. Поэтому, если ответ в принципе может быть кэширован, то в запрос в бэкенду не включаются cookie, переданные клиентом. Однако возможна конфигурация, когда бэкенд сам указывает, какие ответы нужно кэшировать, а какие - нет. В этом случае можно разрешить передачу cookie бэкенду.
Директива передаёт заголовки "Cookie", приходящие от клиента, и заголовки "Set-Cookie", переданные от бэкенда, но никак не влияет на их кэширование.
Директива определяет, нужно ли сохранять заголовок "Server", установленный бэкендом, или же этот заголовок должен быть установлен фронтендом.
Возможность устанавливать собственный заголовок "Server" появилась в Apache 1.3.24, и если с этой версией Apache используется mod_accel более ранний, чем 1.0.16, то клиенту будет передаваться заголовок "Server", установленный бэкендом. По умолчанию эта директива выключена и mod_accel-1.0.16, как и предыдущие версии, не передаёт заголовок бэкенда "Server".
При использовании с Apache 1.3.26 и старше и mod_accel версий 1.0.16-1.0.20 заголовок "Server" вообще не выдаётся, если директива выключена. Исправлено в mod_accel-1.0.21.
Директива определяет, нужно ли передавать клиенту заголовок "X-Accel-Expires", установленный бэкендом. Эта директива полезна при использовании каскада из двух mod_accel, тогда на сервере, более близком к бэкенду, нужно разрешить передачу X-Accel-Expires для первого фронтенда.
Директива определяет, нужно ли пытаться соединиться с другим бэкендом, если результат ответа равен 5XX и используется примитивное распределение нагрузки и отказоустойчивость.
Директива определяет размер буфера в килобайтах для приёма тела запроса. Если размер последнего превышает размер буфера, то используется временный файл.
Директиву можно применять в случае, если выполняются все нижеперечисленные условия:
авторизация клиента выполняется бэкендом посредством заголовка "Authorization" или cookie;
ответ бэкенда для разных пользователей одинаковый и следовательно может отдаваться из кэша;
авторизация является дешёвой операцией в отличии от генерации тела ответа;
бэкенд умеет возвращать код ответа 304 (HTTP_NOT_MODIFIED) и это является дешёвой операцией по сравнению с генерацией полного ответа.
Если директива активна, то при наличии в кэше ответа на запрос, выполняется запрос к бэкенду с заголовком "If-Modified-Since".
Директива определяет, какие URL в заголовках "Location" и "Refresh" должны корректироваться. Например, если задана директива
и заголовок "Location" содержит "http://backend/test/two.html", то он будет изменён на "http://frontend/test/two.html".AccelReverse / http://backend/
Директива AccelReverse аналогична директиве ProxyPassReverse модуля mod_proxy, однако её не нужно, да и нельзя, использовать совместно с директивой AccelPass, поскольку AccelPass уже имеет функциональность AccelReverse. Область применения директивы AccelReverse использование mod_accel совместно с модулем mod_rewrite.
Директива определяет размер буфера в килобайтах для передачи ответа бэкенда клиенту.
Директива определяет, добавлять или нет заголовок "X-Host" в запрос, передаваемом бэкенду. В этом заголовке передаётся содержимое заголовка "Host", переданное фронтенду клиентом.
Директива определяет, добавлять или нет заголовок "X-Real-IP" в запрос, передаваемом бэкенду. В этом заголовке передаётся IP-адрес, с которого был сделан запрос к фронтенду.
Директива определяет, добавлять или нет заголовок "X-URI" в запрос, передаваемом бэкенду. В этом заголовке передаётся URI, переданный фронтенду клиентом.
Директива определяет, добавлять или нет заголовок "X-URL" в запрос, передаваемом бэкенду. В этом заголовке передаётся URL, переданный фронтенду клиентом.
Директива задаёт таймауты при работе с бэкендом.
Первый параметр определяет таймаут при передаче запроса бэкенду и чтении его
ответа. Второй параметр определяет таймаут на соединение с бэкендом.
Оба параметра можно задавать в виде строки, например,
Задавать большой таймут при работе с бэкендом имеет смысл в том случае, если до истечения таймаута ответ от бэкенда всё же может быть получен и этот ответ кэшируется. Тогда последующие запросы будут отдаваться из кэша до тех пор, пока ответ не устареет. В этом случае рекомендуется устанавливать директивой AccelBusyLock значения busy lock'ов большие, чем значение таймаута.
Задавать небольшие значения обоих таймаутов рекомендуется для реализации примитивного распределения нагрузки и отказоустойчивости.
Директива определяет, нужно ли удалять из кэша ответы, даже если они не могут быть закэшированы.
Директива определяет время ожидания в миллисекундах между первым и вторым чтением ответа бэкенда.
Модуль mod_accel работает с бэкендами, поддерживающими протокол HTTP/1.0 и выше.
Модуль mod_accel делает запрос к бэкенду по протоколу HTTP/1.0.
Если на фронтенде добавляется несколько заголовков "Set-Cookie", то в ответ, отдаваемый модулем mod_accel, добавляется только один такой заголовок.
Модуль mod_accel не поддерживает метод TRACE.
Модуль, возможно, будет собираться на не-Unix платформах, но никаких телодвижений по портированию не делалось.
При сборке mod_accel так же собирается менеджер кэша при условии,
что mod_accel не был сконфигурирован
с параметром --without-cachemgr
.
С помощью менеджера кэша можно обновлять или удалять отдельные URL в кэше.
Для того, что бы менеджер кэша был доступен по запросу "/cachemgr",
нужно задать такие директивы:
После этого менеджер кэша может быть вызван с двумя параметрами "/cachemgr?action=<action>&url=<url>", причём url должен быть обязательно последним. Параметр action может принимать два значения: refresh для обновления содержимого кэша и remove для удаления файла из кэша. Параметр url должен задаваться без префикса "http://", имени хоста и порта. При ответе cachemgr добавляет три заголовка:<Location /cachemgr> SetHandler "accel-cachemgr" </Location>
X-Accel-Cachemgr-Action указывает, какое действие было предпринято менеджером. Может принимать следующие значения: create файл кэша был создан, refresh файл кэша был обновлён, remove файл кэша был удалён.
X-Accel-Cachemgr-URL указывает URL, который был задан менеджеру.
X-Accel-Cachemgr-Status указывает результат выполнения операции. Может принимать следующие значения:
success операция выполнена успешно;
invalid ошибка в параметрах, переданных менеджеру кэша;
no_accelerated запрос не обрабатывается модулем mod_accel;
not_found файл в кэше не найден (при операции remove)
или бэкенд вернул
no_cachable ответ бэкенда некэшируем;
cache_error ошибка при работе с кэшом;
backend_error ошибка при работе с бэкендом.
Модуль mod_randban подставляет случайное число в ответах модуля mod_accel.
Директива указывает искать заданную строку и заменять следующее за ней число случайным числом. Максимальное число заменяемых символов указывается во втором параметре директивы. При этом идущие подряд одинаковые числа будут меняться на одинаковые случайные числа. Например, директивы
заменит текстRandomBanner random=rb 10 RandomBanner rand= 10
<a href="http://host/path0?place=1&random=rb00000">
<img src="http://host/path1?place=1&random=rb00000">
</a>
<a href="http://host/path0?place=1&key=1234">
<img src="http://host/path1?place=1&key=1234&rand=11111">
</a>
<a href="http://host/path0?place=1&random=rb00000">
<img src="http://host/path1?place=1&random=rb00000">
</a>
на такой:
<a href="http://host/path0?place=1&random=rb42943">
<img src="http://host/path1?place=1&random=rb42943">
</a>
<a href="http://host/path0?place=1&key=1234">
<img src="http://host/path1?place=1&key=1234&rand=31520">
</a>
<a href="http://host/path0?place=1&random=rb06172">
<img src="http://host/path1?place=1&random=rb06172">
</a>
Модуль mod_quoted перекодирует русские символы в ответах
модуля mod_accel, представленные в виде quoted printable,
в конструкциях вида '<a href="/show?page=2&word=%80%81%82">'.
Такие конструкции обычно используются при выдаче результатов
поиска для ссылок на оставшиеся страницы с результатами поиска.
Символы перекодируются только в ссылках вида
Директива разрешает или запрещает перекодирование quoted printable символов.
Модуль mod_freeze замораживает слишком активные теги и параметры в ответах модуля mod_accel:
Этот модуль можно использовать при проксировании web-почты для предотвращения несанкционированного доступа к почтовым ящикам. Естественно, подобные замены лучше осуществлять на самом сервере web-почты, но это не всегда возможно.
Директива задаёт строку, после которой замораживаются теги и параметры. По умолчанию замораживание начинается с самого начала ответа.
До версии mod_accel 1.0.23 по умолчанию замораживание начиналось после тэга body. Кроме того, директиву можно было задать только глобально для всего сервера.
Директива разрешает или запрещает изменение тегов.
Хотя при установке mod_accel модуль mod_proxy продолжает работать,
это не относится к флагу P директивы
RewriteRule модуля mod_rewrite,
если, конечно, модуль mod_accel не был сконфигурирован с параметром
--without-mod_rewrite
.
При использовании mod_accel можно использовать в директиве RewriteRule флаги MC, MW и MP, как в директиве AccelPass:
за одним исключением в флаге MP нельзя использовать значение L.RewriteRule ^/one.html$ http://backend/$1 [P,MC=10,MP=Tsome]
Поддержка флага MP в директиве RewriteRule появилась в mod_accel, начиная с 1.0.6. В более ранних версиях ресурс можно ограничивать только именем бэкенда.
Первый параметр директивы RewriteRule можно использовать в SSI, например:
<!--#include virtual="/one.html?arg=one" -->
Полная поддержка директивы RewriteRule обеспечена в mod_accel, начиная с версии 1.0.5.
Начиная с mod_accel версии 1.0.10, с помощью директивы AccelReverse можно корректировать заголовки "Location" и "Refresh":
AccelReverse / http://backend/
Использование директив AccelIgnoreNoCache, AccelIgnoreAuth, AccelBusyLock, AccelMaxStale и ограничение числа соединений позволяет уменьшить нагрузку на бэкенд, отдавая закэшированные ответы.
Увеличение размера буфера приёма данных от бэкенда директивой
AccelBkRcvBuffSize позволяет избежать
использования временного файла в качестве буфера.
Для кэшируемых ответов это не так критично, поскольку
этот же временный файл впоследствии будет перелинкован в файл кэша.
Если размер ответа превышает размер буфера в памяти,
то в ErrorLog пишется предупреждение:
Установка директивы AccelUnlinkNoCached в состояние off позволяет не считать хеш-функцию md5 для запросов, которые точно не будут кэшироваться.
Поскольку системные вызовы являются достаточно дорогостоящими операциями, то минимизация их числа ведёт к увеличению производительности системы. Рассмотрим способы уменьшения числа системных вызовов при работе mod_accel.
Если фронтенд и бэкенд соединены ethernet'ом, то ответ зачастую читается блоками по 1460 байт или блоками размером кратным 1460. В этом случае ответ размером 20K может быть считан за 10-15 пар системных вызовов select() и read(). Если же с помощью директивы AccelWaitBeforeBodyRead подождать 200-300 миллисекунд прежде, чем читать тело ответа, то, вполне вероятно, что ядро за это время примет если не весь ответ, то хотя бы его большую часть, и ответ будет считан всего за одну или несколько пар системных вызовов select() и read(). Разумеется, ядро не сможет принять весь ответ за раз, если размер его буфера меньше размера ответа, поэтому, возможно, нужно будет увеличить размер TCP-буфера приёма в ядре директивой AccelBkRcvSockBuffSize. Кроме того, для того, что бы весь ответ был считан из TCP-буфера ядра за один раз необходимо, что бы размер буфера, задаваемый директивой AccelBkRcvBuffSize был не меньше размер буфера TCP-буфера ядра. Проанализировать действие вышеописанных директив можно с помощью заметок "accel_bnr", "accel_bfr", "accel_br", в которых записывается соответственно число чтений бэкенда, размер заголовка ответа и части ответа, считанной за первое чтение, и полный размер ответа.
Увеличение размера буфера отправки данных клиенту директивой AccelSendSize позволяет уменьшить число системных вызовов select() и write(). Необходимо заметить, что select() используется только в случае, когда параллельно с отправкой данных клиенту происходит чтение ответа от бэкенда. Если же ответ полностью считан, то используется только блокирующий write().
Увеличение размера буфера отправки данных клиенту директивой AccelCacheSendSize позволяет уменьшить число системных вызовов read() для чтения ответа из кэша и write() для отправки данных клиенту.
Параметр noauto в директиве AccelCacheRoot позволяет не делать системных вызовов mkdir() для создания промежуточных каталогов при каждом создании нового файла кэша.
Хотя модуль mod_proxy часто используется как буфер между тяжёлым сервером (mod_perl) и медленным клиентом, он плохо справляется с этой задачей. Это связано с тем, что mod_proxy читает ответ от бэкенда блоками по 8K и такими же блоками отдаёт его клиенту. После получения всего ответа mod_proxy вызвает функцию ap_bflush(), которая записывает оставшиеся данные из внутреннего буфера Apache размером 4K в сокет клиента. И лишь после этого mod_proxy закрывает сокет бэкенда. Если в качестве бэкенда используется Apache, то после передачи всех данных фронтенду, он выполняет функцию lingering_close() делает shutdown() на запись в сокет и, подождав в select()'е 2 секунды, закрывает сокет.
Таким образом, вся буферизация по сути выполняется не mod_proxy, а ядром и зависит только от размеров TCP-буферов приёма и отправки в ядре на машине с mod_proxy и от размера TCP-буфера отправки на бэкенде. Рассмотрим варианты ситуаций при работе с медленным клиентом (скорость около 3K/s), которые могут возникнуть на FreeBSD версии 3.0-4.3, где размер этих буферов по умолчанию равен 16K.
Если объём передаваемых данных не превышает размера TCP-буфера отправки на фронтенде, то бэкенд освождается практически сразу же после передачи всех данных фронтенду. Из буфера отправки бэкенда все данные сразу же попадают в буфер приёма фронтенда. mod_proxy быстро считывает их по 8K и записывает в буфер отправки и после этого закрывает сокет к бэкенду.
Если объём передаваемых данных не превышает суммарного размера TCP-буферов отправки и приёма фронтенда, TCP-буфера отправки бэкенда и внутреннего буфера mod_proxy, равного 8K, (в нашем случае суммарный размер 56K), то бэкенд ждёт ещё две секунды после передачи всех данных фронтенду. Это происходит из-за того, что буфер отправки фронтенда заполнен полностью первыми 16K, следующие 8K считаны mod_proxy, ещё 16K находятся в буфере приёма фронтенда и последние 16K находятся в буфере отправки бэкенда. До тех пор, пока фронтенд не передаст клиенту первые 16K (а это займёт около 5 секунд), mod_proxy не сможет записать в буфер отправки оставшиеся данные и соответственно не сможет закрыть сокет к бэкенду.
Если объём передаваемых данных больше суммарного размера TCP-буферов отправки и приёма фронтенда, TCP-буфера отправки бэкенда и внутреннего буфера mod_proxy, то бэкенд занят в течение времени, необходимого для передачи медленному клиенту данных, превышающих суммарный размер буферов, плюс ещё две секунды после передачи всех данных фронтенду.
Надо сказать, что эти дополнительные 2 секунды в Apache нигде не
фиксируются, то есть, их нельзя увидеть в логах во времени выполнения
запроса - %T и в запросе server-status, так как время, затраченное
на lingering_close(), в %T не учитывается и процесс помечается как
свободный в scoreboard ещё до вызова lingering_close().
Единственный способ увидеть эти две секунды - это запусить
команду netstat
на бэкенде и посмотреть, сколько сокетов,
соединяющих бэкенд и фронтенд, находятся в состоянии FIN_WAIT2.
Сокет переходит в это состояние после вызова бэкендом shutdown()
и получения подтверждения от ядра фронтэнда. Однако, при анализе
необходимо учитывать, что сокет может оставаться в этом состоянии
и после того, как бэкенд выждал 2 секунды и вызвал close(), то есть,
уже готов к обработке нового запроса.
Уменьшить время ожидания бэкенда при записи больших ответов можно с помощью
директивы ProxyReceiveBufferSize задающей размер TCP-буфера
приёма в ядре, и SendBufferSize задающей размер TCP-буфера
отправки в ядре.
Кроме того, можно увеличить размеры всех TCP-буферов
на фронтенде и бэкенде средствами операционной системы.
Однако увеличение буфера отправки на фронтенде лишь отдаляет проблему
2-х секундной задержки.
Избежать 2-х секундной задержки можно, если собрать бэкенд с параметром
-DNO_LINGCLOSE
.
В Apache 1.3.24 частично решена проблема взаимодействия mod_proxy и бэкенда появилась директива ProxyIOBufferSize, позволяющая задать размер буфера для получения ответа от бэкенда. Кроме того, если от бэкенда получен весь ответ, то соединение с ним закрывается, что позволяет избежать 2-х секундной задержки. Тем не менее, проблема решена не полностью если размер ответа бэкенда будет больше суммы размера заданного буфера и ядерных TCP-буферов, то бэкенд будет занят на время, необходимое для передачи части ответа, превышающей суммарный размер буферов.
Кроме синхронного получения ответа ответа от бэкенда и отдачи его клиенту, mod_proxy так же синхронно принимает тело запроса клиента и передаёт его бэкенду.
При использовании mod_accel такой проблемы нет, поскольку чтение из сокета бэкенда и запись в сокет клиента выполняются асинхронно, все операции неблокирующие и готовность обоих сокетов проверяется с помощью select()'a. mod_accel считывает ответ от бэкенда в буфер, размер которого задаётся директивой AccelBkRcvBuffSize. Если размер ответа превышает размер буфера, то содержимое буфера записывается во временный файл. Если ответ кэшируемый, то этот временный файл позже перелинковывается в файл кэша. Кроме того, имеется директива AccelBkRcvSockBuffSize, которая так же, как и ProxyReceiveBufferSize позволяет задавать размер TCP-буфера приёма в ядре с тем отличием, что размер задаётся в килобайтах, а не в байтах. Однако в mod_accel она предназначена для уменьшения количества системных вызовов select() и read(), необходимых для чтения ответа бэкенда.
Что касается тела запроса, то оно полностью принимается от клиента и только после этого передаётся бэкенду. Размер буфера для приёма задаётся директивой AccelRequestBuffSize. Если тело запроса больше размера буфера, то оно записывается во временный файл.
(C) 2001, 2002, Igor Sysoev