El progtwig ‘ab’ se congela después de muchas solicitudes, ¿por qué?

Cada vez que uso ‘ab’ para comparar un servidor web, se congelará por un tiempo después de haber enviado muchas solicitudes, solo para continuar después de 20 segundos más o menos.

Considere el siguiente simulador de servidor HTTP, escrito en 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 

Luego corro ab de la siguiente manera:

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

Durante los primeros segundos, ab hace su trabajo como se supone y usa 100% de CPU:

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

Después de aproximadamente 13500 solicitudes, el uso de la CPU del sistema cae al 0%. ab parece estar congelado en algo. El problema no está en el servidor porque en este momento, el servidor está llamando a accept (). Después de unos 20 segundos ab continúa como si nada hubiera sucedido, y usará 100% de CPU nuevamente, solo para congelar nuevamente después de varios segundos.

Sospecho que algo en el kernel está limitando las conexiones, pero ¿qué y por qué? Estoy usando OS X Leopard. También he visto un comportamiento similar en Linux, aunque la congelación ocurre en un número mucho mayor de solicitudes y no ocurre con tanta frecuencia.

Este problema me impide ejecutar grandes puntos de referencia HTTP.

Parece que te estás quedando sin puertos efímeros . Para verificar, use el comando netstat y busque varios miles de puertos en el estado TIME_WAIT .

En Mac OS X, el rango de puerto efímero predeterminado es 49152 a 65535, para un total de 16384 puertos. Puede verificar esto con el comando sysctl :

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

Una vez que se quede sin puertos efímeros, normalmente deberá esperar hasta que el estado TIME_WAIT expire (2 * vida máxima del segmento) hasta que pueda reutilizar un número de puerto particular. Puede duplicar la cantidad de puertos cambiando el rango para comenzar en 32768, que es el valor predeterminado en Linux y Solaris. (El número de puerto máximo es 65535 por lo que no puede boost el extremo superior).

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

Tenga en cuenta que el rango oficial designado por IANA es 49152 a 65535, y algunos cortafuegos pueden asumir que los puertos asignados dinámicamente caen dentro de ese rango. Es posible que necesite reconfigurar su firewall para utilizar un rango mayor fuera de su red local.

También es posible reducir la vida útil máxima del segmento ( sysctl net.inet.tcp.msl en Mac OS X), que controla la duración del estado TIME_WAIT , pero esto es peligroso, ya que podría causar que las conexiones antiguas se mezclen con las más recientes. unos que están usando el mismo número de puerto. También hay algunos trucos que implican la vinculación a puertos específicos con la opción SO_REUSEADDR , o el cierre con la opción SO_LINGER , pero también pueden confundir conexiones antiguas y nuevas, por lo que generalmente se consideran malas ideas.

En lugar de boost la cantidad de puertos, cambie la duración de TIME_WAIT en Mac OS X.

Esto solo funciona en el desarrollo, pero ahora puedo solicitar ab tantas solicitudes como quiera sin tener que agotar el tiempo.

Establezca el tiempo de espera predeterminado en 1000 ms así:

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

La página de brianp.net mencionada en la otra respuesta ya no está disponible. Puede recuperarlo del archivo de internet .

Intereting Posts