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

14

Я управляю сайтом с относительно низким трафиком, который посещает один раз в неделю после обновления сайта. Во время этого скачка производительность сайта очень низкая по сравнению с остальной частью недели. Фактически нагрузка на серверы остается очень низкой, надежно ниже 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

(... abdridged)

Если я читаю это правильно (и терпите меня, поскольку я не очень часто использую 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)

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

cmckendry
источник
Возможные варианты: CloudFlare, drupal.org/project/boost , CDN, Varnish cache.
ceejayoz
Вы ничего не говорите нам о том, что делает этот сервер (в реальном мире), кроме обслуживания HTTP-запросов. Включена ли база данных (или какой-либо другой общий ресурс, который может пострадать из-за конфликта блокировок)? Если проблема возникает внезапно при ТОЛЬКО 256 запросах (ОК на 255), возможно, какой-то внешний ресурс затоплен. (Ваш прыжок, обслуживающий статическую страницу, тоже определенно ненормальный - см. Ответ Ладададада, где приведены некоторые советы по отладке)
voretaq7
ceejayoz: Я ценю предложения, но в целом я считаю, что Apache не должен быть таким медленным. Есть много вещей, которые мы можем сделать, чтобы смягчить последствия проблемы, но я бы предпочел исправить или, по крайней мере, понять это.
cmckendry
voretaq7: я изначально думал в том же духе, поскольку типичный запрос также включал бы php / mysql, но проблема сохраняется на том же пороге, даже когда он обслуживает полностью статический контент.
cmckendry
1
Это настоящий сервер или виртуальная машина? Вы делаете свой тест с локального хоста, локальной сети или Интернета? Минимальное время отклика в диапазоне 100 мс предполагает тестирование из Интернета. Попробуйте проверить с localhost - возможно, ваш провайдер просто душит вас.
Томецкий

Ответы:

4

Что бы я сделал в этой ситуации, это запустить

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потенциальных клиентах заколите меня поверить , что ты был бы увидеть около 13 000 пакетов в секунду ( не обращая внимания на 5% медленных запросы). Может быть, это узкое место, которое вы достигли. Тот факт, что это происходит около 256, может быть просто совпадением.

Ladadadada
источник