2009-08-01 21 views
32

Bir web sunucusunu karşılaştırmak için 'ab' kullandığımda, çok fazla istek gönderildikten sonra bir süre donacak ve yalnızca 20 saniye sonra devam edecek. aşağıdaki gibi'ab' programı birçok istekten sonra donuyor, neden?

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 

Sonra ab çalıştırın::

Ruby ile yazılmış aşağıdaki HTTP sunucusu simülatörü, düşünün o gerekiyordu olarak ilk birkaç saniye boyunca

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

, ab işini yapar ve% 100 CPU kullanır:

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

Yaklaşık 13500 istekten sonra, sistem CPU kullanımı düşer. 0%. ab bir şey üzerinde donmuş görünüyor. Sorun şu anda sunucuda değil, sunucu şu anda kabul ediyor(). Yaklaşık 20 saniye sonra, hiçbir şey olmamış gibi devam eder ve tekrar birkaç saniye sonra tekrar dondurmak için tekrar% 100 CPU kullanır.

Çekirdeğindeki bir şeyin bağlantılar arasında sıkıştığından şüpheleniyorum, ama ne ve neden? OS X Leopard kullanıyorum. Dondurucunun çok daha fazla sayıda istekte bulunmasına ve sık sık gerçekleşmemesine rağmen, Linux'ta da benzer davranışlar gördüm.

Bu sorun, büyük bir HTTP karşılaştırması yapmamı engelliyor.

cevap

47

ephemeral ports'dan bitmiş gibi geliyor. Kontrol etmek için netstat komutunu kullanın ve TIME_WAIT durumunda birkaç bin port arayın.

Mac OS X'te varsayılan kısa ömürlü bağlantı noktası aralığı 16384 limanların toplam 65535 49152. Eğer kısa ömürlü bağlantı noktaları tükendi kez belirli bir port numarasını yeniden kullanabilirsiniz kadar

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

, normalde TIME_WAIT devlet (2 * en fazla kesim ömrünü) sona erinceye kadar beklemek gerekir: Sen sysctl komutla kontrol edebilirsiniz . Linux ve Solaris'te varsayılan olan 32768'de başlayacak aralığı değiştirerek bağlantı noktası sayısını ikiye katlayabilirsiniz. official range designated by IANA 65535 49152 olduğunu

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

Not (maksimum bağlantı noktası numarası. 65535 böylece yüksek ucunu artıramazsınız olan) ve bazı güvenlik duvarları bu dinamik olarak atanan bağlantı noktaları bu aralığa denk düşen varsayabiliriz. Yerel ağınızın dışında daha geniş bir aralıktan yararlanmak için güvenlik duvarınızı yeniden yapılandırmanız gerekebilir.

O TIME_WAIT hal süresini kontrol eder, (Mac OS X'te sysctl net.inet.tcp.msl) en fazla kesim ömrünü azaltmak da mümkündür, ancak eski bağlantılar vardır yenilerden bulaşmak neden olabilir bu tehlikelidir aynı port numarasını kullanarak. Ayrıca, SO_REUSEADDR seçeneği ile belirli bağlantı noktalarına bağlanma veya SO_LINGER seçeneği ile kapatmayı içeren bazı hileler de vardır, ancak bunlar eski ve yeni bağlantıların karıştırılmasına da neden olabilir, bu nedenle genellikle kötü fikirler olarak kabul edilir.

+1

Evet, işte bu kadar. MSL'yi http://www.brianp.net/2008/10/03/changing-the-length-of-the-time_wait-state-on-mac-os-x/ adresindeki talimatları izleyerek değiştirdim ve her şey çalışıyor şimdi. Teşekkürler! – Hongli

+0

Çok teşekkürler, bu benim yaşadığım aynı sorunu çözdü. –

+0

Burada bir 'Golang' problemi olduğunu düşünüyordum .. 'ab' den gelen her 16000 isteğin donduğunda – kouton

16

yerine port sayısını artırma, Mac OS X üzerinde gelişiminde

Bu yalnızca eser TIME_WAIT uzunluğunu değiştirmek, ama zaman aşımına uğramadan istediğiniz gibi şimdi birçok istekleri için ab sorabilirsiniz.Varsayılan zaman aşımı şöyle 1000MS için

Seti: Diğer cevapta belirtildiği

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

brianp.net sayfa artık mevcut değil. Bunu internet archive'dan alabilirsiniz.