Pregunta

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 ejecuto 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 el 100% de la 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 no hubiera pasado nada y volverá a utilizar el 100% de la CPU, solo para congelarse nuevamente después de varios segundos.

Sospecho que algo en el núcleo 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 tan a menudo.

Este problema me impide ejecutar grandes puntos de referencia HTTP.

¿Fue útil?

Solución

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

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 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

Una vez que se quede sin puertos efímeros, normalmente deberá esperar hasta que expire el estado TIME_WAIT (2 * duración máxima del segmento) hasta que pueda reutilizar un número de puerto en particular. Puede duplicar el número 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 aumentar la gama alta).

$ 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 firewalls puede suponer que los puertos asignados dinámicamente están dentro de ese rango. Es posible que deba volver a configurar su firewall para utilizar un rango más grande 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 más antiguas se mezclen con las más nuevas que usan 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 podrían causar que se mezclen las conexiones antiguas y nuevas, por lo tanto, generalmente se consideran malas ideas.

Otros consejos

En lugar de aumentar el número de puertos, cambie la longitud de TIME_WAIT en Mac OS X.

Esto solo funciona en desarrollo, pero ahora puedo pedirle a ab todas las solicitudes que desee sin tiempo de espera.

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 brianp.net mencionada en la otra respuesta ya no está disponible. Puede recuperarlo de archivo de internet .

Otra opción para resolver el problema es habilitar HTTP KeepAlive agregando la opción " -k " . Esto hará que ab reutilice las conexiones TCP y, como consecuencia, no agotará todos los puertos disponibles. Por ejemplo:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top