Pergunta

Sempre que eu uso 'ab' a referência de um servidor web, ele irá congelar por um tempo depois de ter lotes enviados de pedidos, apenas para continuar depois de 20 segundos ou assim.

Considere o seguinte simulador de servidor HTTP, escrito em 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

Eu, então, executar ab da seguinte forma:

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

Durante os primeiros segundos, ab faz o seu trabalho, uma vez que é suposto e usa 100% da CPU:

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

Depois de cerca de 13500 pedidos, o uso da CPU do sistema cai para 0%. ab parece ser congelados em algo. O problema não está no servidor, porque, neste momento, o servidor está chamando accept (). Após cerca de 20 segundos ab continua como se nada tivesse acontecido, e vai usar 100% da CPU novamente, só para congelar novamente após alguns segundos.

Eu suspeito algo no kernel está estrangulando conexões, mas o que e por quê? Estou usando OS X Leopard. Eu vi um comportamento semelhante em Linux, bem como, embora o congelamento acontece em um número muito maior de pedidos e não acontece com tanta frequência.

Este problema impede-me de correr benchmarks grande HTTP.

Foi útil?

Solução

Parece que você está funcionando fora do efémero portas . Para verificar, use o href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/netstat.1.html" rel="noreferrer"> netstat comando e olhar por vários milhares de portas na TIME_WAIT estado

No Mac OS X, o intervalo de portas efêmeras padrão é 49152-65535, para um total de 16384 portas. Você pode verificar isso com o href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/sysctl.8.html" rel="noreferrer"> sysctl comando :

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

Uma vez que você correr para fora de portas efêmeras, normalmente você vai precisar esperar até que o estado TIME_WAIT expira (2 * tempo de vida máximo de segmento) até que você pode reutilizar um número de porta específico. Você pode dobrar o número de portas, alterando o intervalo para começar em 32768, que é o padrão no Linux e Solaris. (O número da porta máxima é de 65535 para que você não pode aumentar a parte alta.)

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

Note que a gama oficial designado pela IANA é 49152-65535, e alguns firewalls pode-se supor que as portas atribuídas dinamicamente cair dentro desse intervalo. Você pode precisar reconfigurar o seu firewall, a fim de fazer uso de um fora da faixa maior de sua rede local.

Também é possível reduzir o tempo de vida máximo de segmento (sysctl net.inet.tcp.msl no Mac OS X), que controla a duração do estado TIME_WAIT, mas isso é perigoso, pois pode causar conexões mais velhos para se misturam com os mais novos que estão usando o mesmo número de porta. Existem também alguns truques que envolvem ligação a portas específicas com a opção SO_REUSEADDR, ou fechar com a opção SO_LINGER, mas aqueles também poderia causar velho e novas conexões a serem misturados, por isso são geralmente consideradas como más idéias.

Outras dicas

Em vez de aumentar o número de portas, alterar o comprimento de TIME_WAIT no Mac OS X.

Isso só funciona em desenvolvimento, mas agora eu posso pedir ab para tantos pedidos como eu quero, sem tempo limite.

Definir o tempo limite padrão de 1000ms assim:

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

A página brianp.net mencionado na outra resposta não está mais disponível. Você pode recuperá-lo a partir do arquivo de internet .

Outra opção para resolver o problema é habilitar HTTP KeepAlive adicionando a opção "-k". Isso fará com que ab para reutilizar as conexões TCP e, como consequência, não irá esgotar todas as portas disponíveis. Por exemplo:

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top