Yêu cầu POST được lặp lại với máy chủ cân bằng nginx (trạng thái 499)


8

tải lên gấp đôi

Kể từ khi chúng ta chuyển từ một cá thể Apache đơn giản sang một môi trường cân bằng tải, đôi khi có những vấn đề với các yêu cầu POST được lặp lại. Chúng tôi đang chạy nginx như proxy ngược. Nội dung tĩnh đang được phục vụ bởi chính nginx và nội dung động được phục vụ từ hai phụ trợ Apache.

Tôi đã kiểm tra rằng đó không phải là lỗi giao diện / người dùng. Một ví dụ nhỏ: tải lên hình ảnh đơn giản sẽ dẫn đến hình ảnh được tải lên hai lần. Yêu cầu / POST không được gửi hai lần bằng cách nhấp đúp hoặc lỗi người dùng. Tôi không tìm thấy bất kỳ bằng chứng nào cho thấy trình duyệt đang gửi yêu cầu hai lần, vì vậy sự nghi ngờ của tôi nằm ở phía máy chủ. (Lưu ý rằng đây chỉ là sự nghi ngờ.) Hầu hết các yêu cầu này là nội bộ, có nghĩa là chúng là của nhân viên, vì vậy tôi có thể xác minh cách chúng đến.

Điều duy nhất 'sai' tôi có thể tìm thấy là nginx sẽ ghi lại 499lỗi trong những trường hợp này. Tuy nhiên, tôi không chắc chắn nếu đây là nguyên nhân hay chỉ là tác động (phụ) của vấn đề. (Tôi biết rằng 499 không phải là trạng thái http mặc định, đó là trạng thái nginx có nghĩa là "máy khách có kết nối đóng")

yêu cầu

Các yêu cầu POST lặp đi lặp lại gần như tất cả các yêu cầu có thể mất một lúc. Ví dụ tôi đang hiển thị ở đây là một ví dụ tải lên hình ảnh đơn giản, nhưng tập lệnh thực hiện một số nội dung trong nền (hình ảnh phải được chuyển đổi thành các định dạng / kích thước khác nhau và phải được phân phối cho cả hai máy chủ, v.v.).

nhật ký

Một ví dụ là việc tải lên một hình ảnh. nginx sẽ ghi lại một '499' và một yêu cầu 200, nhưng Apache đang nhận (và xử lý!) hai yêu cầu.

Apache

[17:17:37 +0200] "POST ***URL** HTTP/1. 0" 200 9045   
[17:17:47 +0200] "POST ***URL** HTTP/1. 0" 200 20687

nginx

[17:17:47 +0200] "POST ***URL** HTTP/1.1" 499 0 
[17:17:52 +0200] "POST ***URL** HTTP/1.1" 200 5641

Nghi ngờ

Dường như với tôi rằng các video tải lên lớn hơn / chậm hơn phải chịu đựng điều này nhiều hơn, vì vậy tôi nghi ngờ thời gian chờ. Tôi đã cố gắng đọc lên lỗi 499: kết luận dường như đó là "kết nối máy khách đóng". Đó có thể là trường hợp nền, nhưng tôi không chắc điều này có nghĩa là yêu cầu thứ hai sẽ được đưa ra và chắc chắn không có gì giống như "trình duyệt đóng của người dùng" đang diễn ra.

Hiện tại nó có vẻ giúp phá vỡ các yêu cầu POST chậm hơn (nếu có nhiều việc phải làm, chỉ cần khiến người dùng chọn 1 và POST lần thứ hai cho lần khác), nhưng điều này có thể làm giảm khả năng xảy ra. Không chắc.

Đây rõ ràng là một giải pháp tạm thời. Nếu đó thời gian chờ, tôi cần tìm ra nơi và tăng các con số tương ứng, nhưng tôi không chắc tại sao thời gian chờ lại gây ra hành vi này: Tôi nghi ngờ một thông báo "tốt, đã sai", không lặp lại.

Câu hỏi

Tôi đang tìm hiểu xem quá trình / tình huống nào có thể khiến POST bị lặp lại. Tất nhiên, bất kỳ "không chắc chắn tại sao, nhưng nó sẽ được khắc phục bằng cách tăng thời gian chờ này" cũng rất tuyệt.

cấu hình nginx

NGINX.conf

user  nginx;
worker_processes  2;
worker_rlimit_nofile 10240;

error_log  /var/log/nginx/error.log error;
pid        /var/run/nginx.pid;


events {
    multi_accept on;
    worker_connections  4096;
    use epoll;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nodelay     off;    
    client_max_body_size    30m;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

thú nhận

Tôi đã loại bỏ một số dòng dành riêng cho IP trong các geophần, cũng như các SSLbiến thể, để giữ cho nó đơn giản. Nếu cần tôi có thể thay thế chúng, nhưng nó sẽ chuyển sang geophần bổ sung cho các phụ trợ ssl, và các tệp ngược dòng và conf tương ứng.

geo $backend {
    default apache-backend;
}

upstream apache-backend {
    ip_hash;
    server SERVER1 max_fails=3 fail_timeout=30s weight=2;
    server SERVER2 max_fails=3 fail_timeout=30s weight=3;
}

conf.d / somestring.conf

limit_conn_zone $binary_remote_addr zone=somestring:10m;
server {
    listen ip1:80;
    listen ip2:80;
    server_name name.tld www.name.tld;

    root PATH

    access_log PATH/name.log main;

    location / {
            proxy_pass              http://$backend;
    }

            //*some more locations**//

    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_min_length 1100;
    gzip_buffers 16 8k;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}

conf.d / proxy.conf

proxy_set_header        Accept-Encoding "";
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        Host $http_host;

proxy_buffering         on;
proxy_read_timeout      90;
proxy_buffer_size       32k;
proxy_buffers           8 32k;
proxy_busy_buffers_size    32k;
proxy_temp_file_write_size 32k;

Và bạn đang sử dụng gì cho một bộ cân bằng tải?
Michael Hampton

Proxy ngược nginx là trình cân bằng tải của chúng tôi, tôi đã cố gắng làm cho điều đó rõ ràng hơn bằng cách thay thế trình cân bằng tải bằng 'proxy ngược' trong câu thứ hai đó :)
Nanne

OK, vậy cấu hình nginx của bạn là gì?
Michael Hampton

Tôi không bao gồm nó, vì tôi không chắc điều gì có thể là nguyên nhân của yêu cầu lặp đi lặp lại. Nếu bạn nghi ngờ một thiết lập nào đó nginxcó thể làm điều này, tôi rất muốn nghe suy nghĩ của bạn. Tôi sẽ đăng cài đặt nginx một chút! (Tôi không muốn thực hiện một này "đây là bãi rác của tất cả các thiết lập ngẫu nhiên tôi có thể tìm thấy" câu hỏi, và như tôi hy vọng tôi đã giải thích, tôi đang cố gắng để tìm ra những gì một phần của chuỗi có thể phải chịu trách nhiệm)
Nanne

(nếu mất một lúc, tôi sẽ xóa tất cả những thứ như IP và các thứ khác liên quan đến url)
Nanne

Câu trả lời:


4

Câu trả lời ngắn: hãy thử điều này cho khối vị trí của bạn:

location / {
  proxy_read_timeout 120;
  proxy_next_upstream error;
  proxy_pass http://$backend;
}

Giải thích dài hơn:

Tôi nghĩ rằng tôi vừa gặp phải chính xác vấn đề bạn mô tả:

  • Tôi sử dụng proxy ngược nginx làm bộ cân bằng tải
  • đối với các yêu cầu chạy dài, phụ trợ nhận được cùng một yêu cầu nhiều lần
  • nhật ký truy cập nginx của các nút ngược dòng hiển thị 499trạng thái cho các yêu cầu này và cùng một yêu cầu xuất hiện trong các nút ngược dòng khác nhau

Hóa ra đây thực sự là hành vi mặc định cho nginx là proxy ngược và việc nâng cấp nó lên các phiên bản cao hơn sẽ không giải quyết được vấn đề này, mặc dù nó được đưa ra như một giải pháp khả thi ở đây , nhưng điều này giải quyết một vấn đề khác.

Nó xảy ra bởi vì nginx là một bộ cân bằng tải chọn một nút ngược dòng theo kiểu vòng tròn . Khi nút được chọn thất bại, yêu cầu được gửi đến nút tiếp theo. Điều quan trọng cần lưu ý ở đây là lỗi nút được mặc định được phân loại là error or timeout. Vì bạn không đặt a proxy_read_timeout, mặc định là 60 giây. Vì vậy, sau 60 giây chờ đợi, nginx chọn nút tiếp theo và gửi cùng một yêu cầu.

Vì vậy, một giải pháp là tăng thời gian chờ này để hoạt động dài hạn của bạn có thể hoàn thành, ví dụ: bằng cách đặt proxy_read_timeout 120;(hoặc bất kỳ giới hạn nào phù hợp với nhu cầu của bạn).

Một tùy chọn khác là ngăn proxy ngược cố gắng sử dụng nút tiếp theo, trong trường hợp hết thời gian, bằng cách cài đặt proxy_next_upstream error;. Hoặc bạn có thể đặt cả hai tùy chọn này, như được đề xuất ở trên.


Hừm, thú vị! Dường như không có gì sai với câu trả lời của bạn, nhưng trong trường hợp cụ thể của tôi, tôi gặp rắc rối vì việc vô hiệu hóa SPDY đã khắc phục nó; chúng tôi có một số lượng lớn các quy trình chạy dài mà không hiển thị hành vi này (nữa). Có lẽ việc vô hiệu hóa SPDY đã loại bỏ một số loại hành vi thứ cấp ngẫu nhiên sửa lỗi này cho chúng tôi và phương pháp này thậm chí có thể tốt hơn? Chúng tôi đã không có vấn đề này trong một thời gian dài bây giờ. Tôi sẽ xem cài đặt hiện tại của chúng tôi là gì và liệu chúng tôi có thể kết hợp mẹo này ở đâu đó không, cảm ơn!
Nanne

Tôi cũng đã nhìn thấy những chiếc 499 rồi 502 một lần, hóa ra đó là "sự trùng hợp đơn thuần" mặc dù nhìn thấy ở đây: stackoverflow.com/a/58924751/32453 (như một lưu ý NGINX không được phép gửi POST cho máy chủ tiếp theo, theo mặc định, FWIW ...)
rogerdpack

1

Từ chủ đề diễn đàn này, chúng tôi đã học được rằng dấu ấn có thể là SPDY. Đối với người dùng đó, có vẻ như là một giải pháp để vô hiệu hóa nó và chúng tôi cũng không có bài viết kép kể từ khi vô hiệu hóa nó.

Vấn đề chính xác, sau đó là "SPDY đã làm được", hiện tại vẫn chưa rõ, tác dụng phụ của giải pháp được đề xuất (vô hiệu hóa SPDY) rõ ràng là "không còn SPDY", nhưng chúng ta có thể sống với điều đó.

Cho đến khi lỗi nhảy lên một lần nữa, tôi gọi đây là 'sửa chữa' (hoặc ít nhất là: một giải pháp cho vấn đề).

chỉnh sửa: Chúng tôi chưa (25-02-2014) thấy vấn đề này xuất hiện nữa, vì vậy đây thực sự là một giải pháp lâu dài.

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.