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

Производительность Apache резко падает, когда количество одновременных запросов превышает ~ 256

У меня сайт с относительно низким трафиком, на который раз в неделю после обновления сайта наблюдается большой всплеск посетителей. Во время этого скачка производительность сайта крайне низкая по сравнению с остальной частью недели. Фактическая нагрузка на серверы остается очень низкой, надежно ниже 10% ЦП и ниже 30% ОЗУ (оборудование должно быть полностью избыточным для того, что мы на самом деле делаем), но по какой-то причине Apache, похоже, не может справиться с количеством запросов. Мы запускаем apache 2.2.3 на RHEL 5.7, ядро ​​2.6.18-274.7.1.el5, x86_64.

Пытаясь воспроизвести это поведение в нерабочее время с помощью ab, я обнаружил значительное снижение производительности при превышении примерно 256 пользователей. Выполнение теста с наименьшим возможным вариантом использования, который я мог придумать (извлекаемый статический текстовый файл, всего 223 байта), производительность стабильно нормальная при 245 одновременных запросах:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       15   25   5.8     24      37
Processing:    15   65  22.9     76      96
Waiting:       15   64  23.0     76      96
Total:         30   90  27.4    100     125

Percentage of the requests served within a certain time (ms)
  50%    100
  66%    108
  75%    111
  80%    113
  90%    118
  95%    120
  98%    122
  99%    123
 100%    125 (longest request)

Но как только я набираю до 265 одновременных запросов, выполнение некоторых из них начинает занимать абсурдное количество времени:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       13  195 692.6     26    3028
Processing:    15   65  21.3     72     100
Waiting:       15   65  21.3     71      99
Total:         32  260 681.7    101    3058

Percentage of the requests served within a certain time (ms)
  50%    101
  66%    108
  75%    112
  80%    116
  90%    121
  95%   3028
  98%   3040
  99%   3044
 100%   3058 (longest request)

Эти результаты очень стабильны для нескольких прогонов. Поскольку к этому ящику идет другой трафик, я не уверен, где именно будет жесткое отключение, если оно есть, но оно кажется подозрительно близким к 256.

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

<IfModule prefork.c>
StartServers     512
MinSpareServers  512
MaxSpareServers  512
ServerLimit      512
MaxClients       512
MaxRequestsPerChild  5000
</IfModule>

mod_status подтверждает, что сейчас у меня 512 доступных потоков

8 requests currently being processed, 504 idle workers

Однако попытка одновременного выполнения 265 запросов по-прежнему дает почти те же результаты, что и раньше.

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       25  211 714.7     31    3034
Processing:    17   94  28.6    103     138
Waiting:       17   93  28.5    103     138
Total:         57  306 700.8    138    3071

Percentage of the requests served within a certain time (ms)
  50%    138
  66%    145
  75%    150
  80%    161
  90%    167
  95%   3066
  98%   3068
  99%   3068
 100%   3071 (longest request)

После просмотра документации (и Stack Exchange) я не могу найти дальнейшие настройки конфигурации, чтобы попытаться устранить это узкое место. Что-то мне не хватает? Стоит ли мне искать ответы вне apache? Кто-нибудь еще видел такое поведение? Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ:

По совету Ладададады я столкнулся с апачем. Я пробовал с -tt и -T несколько раз и не нашел ничего необычного. Затем я попытался запустить strace -c против всех запущенных в данный момент процессов apache и получил следующее:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 22.09    0.317836           5     62128      4833 open
 19.91    0.286388           4     65374      1896 lstat
 13.06    0.187854           0    407433           pread
 10.70    0.153862           6     27076           semop
  7.88    0.113343           3     38598           poll
  6.86    0.098694           1    100954     14380 read

(... сокращено)

Если я правильно прочитал (и терпите меня, поскольку я не очень часто использую strace), ни один из системных вызовов не может учитывать количество времени, которое занимают эти запросы. Похоже, что узкое место возникает еще до того, как запросы попадают в рабочие потоки.

РЕДАКТИРОВАТЬ 2:

Как предложили несколько человек, я снова запустил тест на самом веб-сервере (ранее тест запускался из нейтрального Интернет-адреса). Результаты были удивительными:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   11   6.6     12      21
Processing:     5  247 971.0     10    4204
Waiting:        3  245 971.3      7    4204
Total:         16  259 973.3     21    4225

Percentage of the requests served within a certain time (ms)
  50%     21
  66%     23
  75%     24
  80%     24
  90%     26
  95%   4225
  98%   4225
  99%   4225
 100%   4225 (longest request)

Итоговое время аналогично интернет-тесту, но, по-видимому, постоянно немного ниже. хуже при локальном запуске. Что еще более интересно, профиль сильно изменился. Если раньше большая часть времени длительных запросов уходила на «соединение», то теперь узкое место, похоже, связано либо с обработкой, либо с ожиданием. Мне остается подозревать, что это может быть отдельная проблема, которая ранее маскировалась сетевыми ограничениями.

Запуская тест снова с другого компьютера в той же локальной сети, что и хост Apache, я вижу гораздо более разумные результаты:

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    2   0.8      2       4
Processing:    13  118  99.8    205     222
Waiting:       13  118  99.7    204     222
Total:         15  121  99.7    207     225

Percentage of the requests served within a certain time (ms)
  50%    207
  66%    219
  75%    220
  80%    221
  90%    222
  95%    224
  98%    224
  99%    225
 100%    225 (longest request)

Эти два теста вместе вызывают ряд вопросов, но отдельно от этого теперь есть веские основания для серьезного узкого места в сети, возникающего при определенной нагрузке. Я думаю, что следующие шаги будут посвящены отдельному исследованию сетевого уровня.

Что бы я сделал в этой ситуации, так это бегу

strace -f -p <PID> -tt -T -s 500 -o trace.txt

на одном из ваших процессов Apache во время теста ab, пока вы не зафиксируете один из медленных ответов. Тогда посмотрите trace.txt.

В -tt и -T Параметры дают вам отметки времени начала и продолжительности каждого системного вызова, чтобы помочь идентифицировать медленные.

Вы можете найти один медленный системный вызов, например open() или stat() или вы можете быстро позвонить (возможно, несколько) poll() звонит сразу после него. Если вы найдете тот, который работает с файлом или сетевым подключением (что весьма вероятно), просмотрите трассировку назад, пока не найдете этот файл или дескриптор подключения. Более ранние вызовы того же дескриптора должны дать вам представление о том, что poll() ждал.


Хорошая идея, глядя на -c вариант. Удостоверились ли вы, что отслеживаемый вами дочерний элемент Apache за это время обслужил хотя бы один из медленных запросов? (Я даже не уверен, как бы вы это сделали, кроме бега strace одновременно на всех детей.)

К сожалению, strace не дает нам полного представления о том, что делает запущенная программа. Он отслеживает только системные вызовы. Внутри программы может произойти многое, для чего не нужно ни о чем просить ядро. Чтобы выяснить, происходит ли это, вы можете посмотреть отметки времени начала каждого системного вызова. Если вы видите значительные пробелы, значит, время идет. Это нелегко исправить, и в любом случае между системными вызовами всегда есть небольшие промежутки.

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


Если присмотреться к выходу из ab:

Внезапный скачок времени отклика (похоже, что время отклика отсутствует где-либо между 150 мс и 3000 мс) предполагает, что где-то происходит определенный тайм-аут, который срабатывает при более чем 256 одновременных соединениях. Можно было бы ожидать более плавной деградации, если бы у вас не хватало оперативной памяти или циклов процессора при нормальном вводе-выводе.

Во-вторых, медленный ab ответ показывает, что 3000 мс были потрачены в connect фаза. Почти все они заняли около 30 мс, но 5% заняли 3000 мс. Это говорит о том, что проблема в сети.

Куда ты бежишь ab из? Можете ли вы попробовать его из той же сети, что и компьютер Apache?

Для получения дополнительных данных попробуйте запустить tcpdump на обоих концах соединения (желательно с ntp работает на обоих концах, чтобы вы могли синхронизировать два захвата.) и ищите любые повторные передачи tcp. Wireshark особенно хорош для анализа дампов, потому что он выделяет повторные передачи TCP другим цветом, что упрощает их поиск.

Возможно, также стоит посмотреть журналы любых сетевых устройств, к которым у вас есть доступ. Недавно я столкнулся с проблемой с одним из наших брандмауэров, когда он мог обрабатывать пропускную способность в килобайтах в секунду, но не мог обрабатывать количество пакетов в секунду, которые он получал. Он превысил 140 000 пакетов в секунду. Немного быстрой математики на вашем ab run наводит меня на мысль, что вы бы видели около 13 000 пакетов в секунду (без учета 5% медленных запросов). Может быть, вы достигли узкого места. Тот факт, что это происходит около 256, может быть чистым совпадением.