2009-08-01 29 views
32

Bất cứ khi nào tôi sử dụng 'ab' để đánh giá một máy chủ web, nó sẽ đóng băng một lúc sau khi đã gửi nhiều yêu cầu, chỉ để tiếp tục sau 20 giây hoặc lâu hơn.Chương trình 'ab' bị đóng băng sau nhiều yêu cầu, tại sao?

Hãy xem xét các mô phỏng máy chủ HTTP sau, viết bằng 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 

sau đó tôi chạy ab như sau:

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

Trong vài giây đầu tiên, ab làm công việc của mình vì nó là nghĩa vụ phải và sử dụng CPU 100%:

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

Sau khoảng 13500 yêu cầu, mức sử dụng CPU hệ thống giảm o 0%. ab dường như bị đóng băng trên một cái gì đó. Vấn đề không có trong máy chủ bởi vì tại thời điểm này, máy chủ đang gọi accept(). Sau khoảng 20 giây ab tiếp tục như thể không có gì xảy ra, và sẽ sử dụng CPU 100% một lần nữa, chỉ để đóng băng lại sau vài giây.

Tôi nghi ngờ điều gì đó trong hạt nhân đang điều chỉnh các kết nối, nhưng điều gì và tại sao? Tôi đang sử dụng OS X Leopard. Tôi đã nhìn thấy hành vi tương tự trên Linux là tốt, mặc dù đóng băng xảy ra ở một số lượng lớn hơn nhiều yêu cầu và không xảy ra quá thường xuyên.

Sự cố này ngăn tôi chạy các tiêu chuẩn HTTP lớn.

Trả lời

47

Có vẻ như bạn đang chạy hết số ephemeral ports. Để kiểm tra, sử dụng lệnh netstat và tìm kiếm hàng nghìn cổng ở trạng thái TIME_WAIT.

Trên Mac OS X, khoảng thời gian tạm thời mặc định là 49152 đến 65535, với tổng số 16384 cổng. Bạn có thể kiểm tra điều này với sysctl lệnh:

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

Một khi bạn chạy ra khỏi cổng không lâu, bạn sẽ thường cần phải chờ đợi cho đến khi tình trạng TIME_WAIT hết hạn (2 * tối đa phân khúc đời) cho đến khi bạn có thể tái sử dụng một số cổng cụ . Bạn có thể tăng gấp đôi số lượng cổng bằng cách thay đổi phạm vi để bắt đầu tại 32768, đây là mặc định trên Linux và Solaris. (Các số cổng tối đa là 65535, do đó bạn không thể tăng cao.)

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

Lưu ý rằng official range designated by IANA là 49.152-65.535, và một số bức tường lửa có thể giả định rằng các cổng được gán động nằm trong phạm vi đó. Bạn có thể cần định cấu hình lại tường lửa của mình để sử dụng phạm vi rộng hơn bên ngoài mạng cục bộ của mình.

Cũng có thể giảm thời lượng phân đoạn tối đa (sysctl net.inet.tcp.msl trên Mac OS X), điều khiển thời lượng của trạng thái TIME_WAIT, nhưng điều này rất nguy hiểm vì nó có thể khiến các kết nối cũ hơn bị trộn lẫn sử dụng cùng một số cổng. Ngoài ra còn có một số thủ thuật liên quan đến các cổng cụ thể với tùy chọn SO_REUSEADDR hoặc đóng tùy chọn SO_LINGER, nhưng cũng có thể khiến các kết nối cũ và mới bị lẫn lộn, vì vậy thường được coi là ý tưởng tồi.

+1

Vâng, đúng vậy. Tôi đã thay đổi MSL bằng cách làm theo các hướng dẫn tại http://www.brianp.net/2008/10/03/changing-the-length-of-the-time_wait-state-on-mac-os-x/ và mọi thứ hoạt động hiện nay. Cảm ơn! – Hongli

+0

Cảm ơn rất nhiều, điều này cố định cùng một vấn đề tôi đã gặp phải. –

+0

Ở đây tôi đã nghĩ đó là một vấn đề 'Golang' .. khi nó đóng băng mỗi 16000 yêu cầu từ' ab' – kouton

16

Thay vì tăng số lượng cổng, thay đổi độ dài của TIME_WAIT trên Mac OS X.

chỉ này hoạt động trong sự phát triển, nhưng bây giờ tôi có thể yêu cầu ab cho bao nhiêu yêu cầu như tôi muốn mà không cần thời gian ra.

Set thời gian chờ mặc định để 1000ms như vậy:

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

Trang brianp.net đề cập trong câu trả lời khác là không còn nữa. Bạn có thể truy xuất nó từ internet archive.

Các vấn đề liên quan