Nginx proxy_read_timeout so với proxy_connect_timeout


15

Tôi đã bắt đầu sử dụng Nginx làm proxy ngược cho một nhóm máy chủ cung cấp một số loại dịch vụ.

Dịch vụ đôi khi có thể khá chậm (đôi khi chạy trên Java và JVM đôi khi bị kẹt trong "bộ sưu tập rác đầy đủ" có thể mất vài giây), vì vậy tôi đã đặt thành proxy_connect_timeout2 giây, điều này sẽ cho Nginx đủ thời gian để tìm ra ra rằng dịch vụ bị kẹt trên GC và sẽ không đáp ứng kịp thời và nó sẽ chuyển yêu cầu đến một máy chủ khác.

Tôi cũng đã thiết lập proxy_read_timeoutđể ngăn chặn proxy ngược bị kẹt nếu bản thân dịch vụ mất quá nhiều thời gian để tính toán phản hồi - một lần nữa, nó sẽ chuyển yêu cầu đến một máy chủ khác đủ miễn phí để trả lời phản hồi kịp thời.

Tôi đã chạy một số điểm chuẩn và tôi có thể thấy rõ rằng proxy_connect_timeouthoạt động chính xác khi một số yêu cầu trả về chính xác thời gian đã hết cho thời gian chờ kết nối, vì dịch vụ bị kẹt và không chấp nhận kết nối đến (dịch vụ đang sử dụng Jetty dưới dạng nhúng thùng chứa servlet). Công cụ này proxy_read_timeoutcũng hoạt động, vì tôi có thể thấy các yêu cầu trả về sau khi hết thời gian được chỉ định ở đó.

Vấn đề là tôi đã dự kiến ​​sẽ thấy một số yêu cầu hết thời gian chờ proxy_read_timeout + proxy_connect_timeouthoặc gần hết thời gian đó, nếu dịch vụ bị kẹt và không chấp nhận kết nối khi Nginx cố gắng truy cập, nhưng trước khi Nginx có thể hết thời gian - nó sẽ được phát hành và bắt đầu xử lý, nhưng quá chậm và Nginx sẽ hủy bỏ vì hết thời gian đọc. Tôi tin rằng dịch vụ có những trường hợp như vậy, nhưng sau khi chạy một số điểm chuẩn, tổng cộng hàng triệu yêu cầu - tôi đã không thấy một yêu cầu duy nhất trả về bất cứ điều gì ở trên proxy_read_timeout(đó là thời gian chờ lớn hơn).

Tôi sẽ đánh giá cao bất kỳ nhận xét nào về vấn đề này, mặc dù tôi nghĩ rằng đó có thể là do lỗi của Nginx (tôi vẫn chưa xem mã, vì vậy đây chỉ là giả định) rằng bộ đếm thời gian chờ không được đặt lại sau khi kết nối là thành công, nếu Nginx không đọc bất cứ thứ gì từ máy chủ ngược dòng.


1
Phiên bản NGINX nào? Tôi nghĩ rằng tôi nhớ một cái gì đó tương tự trong một phiên bản cũ hơn (có thể khoảng 0,6 / 7) nhưng nó đã được sửa trong một phiên bản mới hơn (Phiên bản ổn định mới nhất là 1.0.5), nhưng điều đó có thể sai. Vẫn biết phiên bản của bạn sẽ có ích
Smudge

Lưu ý rằng các tài liệu nói proxy_read_timeoutkhông phải là "thời gian chờ toàn cầu", mà là giữa 2 thao tác đọc.
poige

@Sam: Tôi đang sử dụng Nginx 1.0.0. @poige - vâng, tôi biết điều đó, đó là lý do tại sao tôi mong đợi tổng thời gian chờ là proxy_read_timeout + proxy_connect_timeout.
Guss

1
Là một lưu ý phụ, có lẽ bạn nên nghiên cứu một số điều chỉnh bộ sưu tập rác đồng thời cho JVM của mình: en.wikipedia.org/wiki/ mẹo
đa thức

@polynomial: chúng tôi đã làm nhưng theo điểm chuẩn của chúng tôi, tính năng thu gom rác đồng thời dẫn đến mất nhiều thời gian CPU hơn so với GC "dừng thế giới", do đó chúng tôi thích đầu tư vào điều chỉnh Nginx :-)
Guss

Câu trả lời:


18

Tôi thực sự không thể tái tạo điều này trên:

2011/08/20 20:08:43 [notice] 8925#0: nginx/0.8.53
2011/08/20 20:08:43 [notice] 8925#0: built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
2011/08/20 20:08:43 [notice] 8925#0: OS: Linux 2.6.39.1-x86_64-linode19

Tôi thiết lập điều này trong nginx.conf của tôi:

proxy_connect_timeout   10;
proxy_send_timeout      15;
proxy_read_timeout      20;

Sau đó tôi thiết lập hai máy chủ thử nghiệm. Một cái sẽ hết thời gian chờ trên SYN và một cái sẽ chấp nhận kết nối nhưng không bao giờ trả lời:

upstream dev_edge {
  server 127.0.0.1:2280 max_fails=0 fail_timeout=0s; # SYN timeout
  server 10.4.1.1:22 max_fails=0 fail_timeout=0s; # accept but never responds
}

Sau đó, tôi đã gửi trong một kết nối thử nghiệm:

[m4@ben conf]$ telnet localhost 2480
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
Host: localhost

HTTP/1.1 504 Gateway Time-out
Server: nginx
Date: Sun, 21 Aug 2011 03:12:03 GMT
Content-Type: text/html
Content-Length: 176
Connection: keep-alive

Sau đó xem error_log cho thấy điều này:

2011/08/20 20:11:43 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://10.4.1.1:22/", host: "localhost"

sau đó:

2011/08/20 20:12:03 [error] 8927#0: *1 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 127.0.0.1, server: ben.dev.b0.lt, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:2280/", host: "localhost"

Và sau đó là access.log có thời gian chờ 30 giây dự kiến ​​(10 + 20):

504:32.931:10.003, 20.008:.:176 1 127.0.0.1 localrhost - [20/Aug/2011:20:12:03 -0700] "GET / HTTP/1.1" "-" "-" "-" dev_edge 10.4.1.1:22, 127.0.0.1:2280 -

Đây là định dạng nhật ký tôi đang sử dụng bao gồm thời gian chờ ngược dòng riêng lẻ:

log_format  edge  '$status:$request_time:$upstream_response_time:$pipe:$body_bytes_sent $connection $remote_addr $host $remote_user [$time_local] "$request" "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $edge $upstream_addr $upstream_cache_status';

1
Câu hỏi của tôi ở trên, trong kịch bản của bạn, giống như thế này: giả sử một máy chủ thử nghiệm chấp nhận kết nối sau một thời gian ngẫu nhiên trong khoảng từ 0 đến 20 giây, sau đó đợi một khoảng thời gian ngẫu nhiên từ 19 giây đến 21 giây trước khi trả lời. Sau đó chạy một điểm chuẩn đơn giản chống lại nó. Tôi hy vọng sẽ thấy khoảng 50% kết quả yêu cầu với thời gian chờ 10 giây, kết quả 25% với thời gian chờ 20 ~ 30 giây và 25% sẽ nhận được phản hồi thành công. Trong trường hợp như vậy, có bao nhiêu yêu cầu thành công sẽ mất hơn 20 giây để hoàn thành? Trong tiêu chuẩn của tôi, không ai trong số họ - và điều đó làm phiền tôi.
Guss

Tôi đã kiểm tra bằng cách thiết lập mất ngẫu nhiên trên SYN và sau đó có CGI phun ra các dòng thực sự chậm trong khoảng 50 giây. Tôi đã có thể thấy các yêu cầu mất nhiều thời gian hơn cả thời gian chờ kết hợp nhưng vẫn thành công: box.access.log 200: 69.814: 67.100:.: 1579 33 127.0.0.1 test.host - [21/8/2011: 20: 30:52 -0700] "NHẬN / huugs HTTP / 1.1" "-" "-" "-" dev_edge 127.0.0.1:2280 -
đa thức

Ok, đó là lạ ở một cấp độ hoàn toàn khác :-). Một lời giải thích có thể là Nginx cần có thời gian để viết yêu cầu ( proxy_send_timeout) và khi bạn đặt nó lên cao hơn proxy_connection_timeout, điều đó thực sự có thể giải thích cho bất kỳ sự chậm trễ nào trong 20 giây proxy_read_timeout. Khi bạn nói "nhổ ra thật chậm" - ý bạn là gì?
Guss

ngủ 1 giữa các dòng in HTML trong phần thân của phản hồi. Chỉ cần hiển thị cách proxy_read_timeout nằm giữa các lần đọc chứ không phải toàn bộ lần đọc.
đa thức

1
Ah tôi thấy. Chà, đây chắc chắn không phải là trường hợp của tôi và tôi xin lỗi vì đã không làm rõ trong OP của tôi. Trong trường hợp của tôi, máy chủ ứng dụng hoàn thành toàn bộ quá trình xử lý trước khi trả về bất kỳ loại phản hồi nào và sau đó trả lại mọi thứ cùng một lúc - do đó proxy_read_timeout, yêu cầu không hoàn toàn hoặc cho phép hoàn toàn yêu cầu. Điều này cũng giải thích sự khác biệt giữa hành vi bạn nhìn thấy và hành vi tôi thấy.
Guss

3

Vấn đề là tôi đã dự kiến ​​sẽ thấy một số yêu cầu hết thời gian chờ sau proxy_read_timeout + proxy_connect_timeout hoặc gần như khoảng thời gian đó, nếu dịch vụ bị kẹt và không chấp nhận kết nối khi Nginx cố gắng truy cập, nhưng trước khi Nginx có thể hết thời gian - nó được phát hành và bắt đầu xử lý, nhưng quá chậm và Nginx sẽ hủy bỏ vì hết thời gian đọc.

Hết thời gian kết nối có nghĩa là gian hàng TCP khi bắt tay (ví dụ: không có SYN_ACK). TCP sẽ thử gửi lại các SYN, nhưng bạn chỉ được cung cấp trong 2 giây. đến Nginx để sử dụng một Máy chủ khác, vì vậy đơn giản là nó không có thời gian để gửi lại các SYN.

CẬP NHẬT. : Không thể tìm thấy trong tài liệu, nhưng tcpdump cho thấy có 3 giây. sự chậm trễ giữa lần gửi thứ 1 đã được gửi và lần thử thứ 2 để gửi SYN.


Tôi không nghĩ rằng đây chính xác là điều tôi đang hỏi - câu hỏi là: nếu dòng ngược bị kẹt và trả về SYN_ACK sau 1.999 giây, tại sao nginx sẽ không tiếp tục với quá trình ngược dòng hiện tại?
Guss

Chà, bạn có thể sử dụng sniffer nếu bạn muốn chắc chắn chính xác. Nó có thể chỉ ra rằng không có ACK nào trong <2 giây cả.
poige

Tôi thực sự không thể sử dụng trình thám thính vì tôi hy vọng sẽ thấy hành vi này xảy ra khi có tải trọng cao trên hệ thống. Giải thích về việc không bao giờ có ACK sau đó một số X nhưng trước đó 2 giây, ngay cả khi xem xét hàng triệu yêu cầu, có vẻ không hợp lý.
Guss
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.