Подтвердить что ты не робот

"ab" программа зависает после множества запросов, почему?

Всякий раз, когда я использую "ab" для тестирования веб-сервера, он некоторое время замерзает после отправки большого количества запросов, только для продолжения через 20 секунд или около того.

Рассмотрим следующий симулятор HTTP-сервера, написанный на Ruby:

require 'socket'

RESPONSE = "HTTP/1.1 200 OK\r\n" +
           "Connection: close\r\n" +
           "\r\n" +
           "\r\n"

buffer = ""
server = TCPServer.new("127.0.0.1", 3000)  # Create TCP server at port 3000.
server.listen(1024)                        # Set backlog to 1024.
while true
    client = server.accept             # Accept new client.
    client.write(RESPONSE)             # Write a stock "HTTP" response.
    client.close_write                 # Shutdown write part of the socket.
    client.read(nil, buffer)           # Read all data from the socket.  
    client.close                       # Close it.
end

Затем я запускаю ab следующим образом:

ab -n 45000 -c 10 http://127.0.0.1:3000/

В течение первых нескольких секунд ab выполняет свою работу по своему усмотрению и использует 100% процессор:

Benchmarking 127.0.0.1 (be patient)
Completed 4500 requests
Completed 9000 requests
Completed 13500 requests

После примерно 13500 запросов загрузка системного процессора падает до 0%. Кажется, что что-то замерзло. Проблема не в сервере, потому что на данный момент сервер вызывает accept(). Примерно через 20 секунд ab продолжает, как будто ничего не происходит, и снова будет использовать 100% CPU, только чтобы снова заморозить через несколько секунд.

Я подозреваю, что что-то в ядре регулирует соединения, но что и почему? Я использую OS X Leopard. Я тоже видел подобное поведение в Linux, хотя замораживание происходит при гораздо большем числе запросов и не происходит так часто.

Эта проблема не позволяет мне запускать большие тесты HTTP.

4b9b3361

Ответ 1

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

В Mac OS X диапазон эфемерных портов по умолчанию составляет от 49152 до 65535, в общей сложности - 16384 порта. Вы можете проверить это с помощью команды sysctl:

$ sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535

Как только вы закончите эфемерные порты, вам, как правило, нужно подождать, пока истечет срок действия TIME_WAIT (максимальный срок жизни сегмента 2 *), пока вы не сможете повторно использовать определенный номер порта. Вы можете удвоить количество портов, изменив диапазон, чтобы начать с 32768, что по умолчанию используется для Linux и Solaris. (Максимальный номер порта - 65535, поэтому вы не можете увеличить высокий уровень.)

$ sudo sysctl -w net.inet.ip.portrange.first=32768
net.inet.ip.portrange.first: 49152 -> 32768

Обратите внимание, что официальный диапазон обозначенный IANA, составляет 49152 - 65535, а некоторые брандмауэры могут предполагать, что динамически назначенные порты попадают в этот диапазон. Возможно, вам понадобится перенастроить ваш брандмауэр, чтобы использовать более широкий диапазон вне вашей локальной сети.

Также возможно уменьшить максимальное время жизни сегмента (sysctl net.inet.tcp.msl в Mac OS X), которое контролирует продолжительность состояния TIME_WAIT, но это опасно, поскольку это может привести к тому, что старые соединения будут запутаны с новыми которые используют один и тот же номер порта. Также есть некоторые трюки, связанные с привязкой к конкретным портам с опцией SO_REUSEADDR или закрытием с помощью параметра SO_LINGER, но также могут быть смешаны старые и новые соединения, поэтому обычно считаются плохими идеями.

Ответ 2

Вместо увеличения количества портов измените длину TIME_WAIT на Mac OS X.

Это работает только в разработке, но теперь я могу запросить ab столько запросов, сколько захочу без тайминга.

Установите время ожидания по умолчанию на 1000 мс следующим образом:

$ sudo sysctl -w net.inet.tcp.msl=1000
net.inet.tcp.msl: 15000 -> 1000

Страница brianp.net, указанная в другом ответе, больше не доступна. Вы можете получить его из интернет-архива .

Ответ 3

Другой вариант решения этой проблемы - включить HTTP KeepAlive, добавив параметр "-k". Это заставит ab повторно использовать TCP-соединения и, как следствие, не исчерпает все доступные порты. Например:

ab -n 45000 -c 10 -k http://127.0.0.1:3000/