Frage

Jedes Mal, wenn ich ‚ab‘ Benchmark einen Web-Server verwenden, wird es für eine Weile einfrieren, nachdem geschickt viele Anfragen haben, erst nach 20 Sekunden andauern oder so.

Betrachten Sie den folgenden HTTP-Server-Simulator, geschrieben in 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

Ich laufe ab dann wie folgt:

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

Während der ersten paar Sekunden ab macht seinen Job als es soll und nutzt 100% CPU:

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

Nach etwa 13.500 Anfragen, System CPU-Auslastung sinkt 0% bis. ab scheint auf etwas eingefroren werden. Das Problem ist nicht auf dem Server, weil in diesem Moment wird der Server akzeptieren () aufrufen. Nach etwa 20 Sekunden ab weiter, als ob nichts passiert ist, und wird zu 100% CPU wieder verwenden, nur um wieder zu frieren nach einigen Sekunden.

ich etwas im Kernel vermuten Drosselung Verbindungen, aber was und warum? Ich bin mit OS X Leopard. Ich habe auf Linux als auch ein ähnliches Verhalten gesehen, obwohl das Einfrieren bei einer viel größeren Anzahl von Anfragen geschieht und nicht geschieht so oft.

Dieses Problem hindert mich daran, läuft großes HTTP-Benchmarks.

War es hilfreich?

Lösung

Es klingt wie Sie aus ephemeren Ports rel="noreferrer">. Um zu überprüfen, verwenden Sie die netstat Befehl und schauen für mehrere tausend Ports in der TIME_WAIT Zustand

Unter Mac OS X der Standard temporäre Portbereich ist 49.152 bis 65.535, für insgesamt 16.384 Ports. Sie können dies mit dem sysctl Befehl ein:

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

Sobald Sie aus temporären Ports ausführen, werden Sie in der Regel müssen warten, bis der TIME_WAIT Zustand abläuft (2 * maximale Segmentlebenszeit), bis Sie eine bestimmte Portnummer wiederverwenden können. Sie können die Anzahl der Ports verdoppeln, indem Sie den Bereich bei 32.768 starten zu ändern, die der Standard unter Linux und Solaris ist. (Die maximale Portnummer 65535, so dass Sie nicht das High-End erhöhen.)

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

Beachten Sie, dass die bezeichneten offiziellen Bereich rel="noreferrer"> ist 49.152-65.535, und einige Firewalls kann davon ausgehen, dass dynamisch zugewiesenen Ports innerhalb dieses Bereichs fallen. Möglicherweise müssen Sie Ihre Firewall, um neu zu konfigurieren Verwendung eines größeren Bereichs außerhalb des lokalen Netzwerks zu machen.

Es ist auch möglich, die maximale Segmentlebensdauer (sysctl net.inet.tcp.msl auf Mac OS X) zu reduzieren, was die Dauer des TIME_WAIT Staates kontrolliert, aber das ist gefährlich, da es ältere Verbindungen zu verwechseln mit neueren dazu führen könnte, dass verwenden die gleiche Portnummer. Darüber hinaus gibt es einige Tricks, die Bindung an bestimmte Ports mit der SO_REUSEADDR Option mit oder Schließen der SO_LINGER Option, aber die könnte auch dazu führen, alte und neue Verbindungen gemischt werden, sind so allgemein schlechte Ideen angesehen werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top