A solicitação POST é repetida com o servidor nginx loadbalanced (status 499)

7

uploads duplos

Desde que passamos de uma simples instância do Apache para um ambiente de balanceamento de carga, às vezes há problemas com as solicitações de POST sendo repetidas. Estamos executando o nginx como proxy reverso. O conteúdo estático está sendo servido pelo próprio nginx, e o conteúdo dinâmico é servido a partir de dois backends do Apache.

Eu verifiquei que não é um erro de interface / usuário. Uma pequena instância por exemplo: um simples upload de imagem resultará na obtenção da imagem duas vezes. A solicitação / POST não é enviada duas vezes clicando duas vezes ou com falha do usuário. Eu não encontrei nenhuma evidência de que o navegador está enviando a solicitação duas vezes, então minha suspeita está no lado do servidor. (Observe que isso é apenas suspeita.) A maioria dessas solicitações é interna, o que significa que elas são de funcionários, para que eu possa verificar como elas acontecem.

A única coisa "errada" que consigo encontrar é que o nginx registra um erro 499 nesses casos. No entanto, não tenho certeza se essa é a causa ou apenas um efeito (colateral) do problema. (Estou ciente de que 499 não é um status http padrão, é um status nginx que significa "cliente fechou conexão")

solicitações

As solicitações POST repetidas são quase todas as solicitações que podem demorar um pouco. O que estou mostrando aqui como exemplo é um simples upload de imagem, mas o script faz algumas coisas em segundo plano (a imagem deve ser convertida em diferentes formatos / tamanhos e deve ser distribuída para ambos os servidores, etc.).

logs

Um exemplo é o upload de uma imagem. O nginx registrará um '499' e um pedido de 200, mas o Apache está recebendo (e manipulando!) dois pedidos.

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

Suspeitas

Parece-me que os uploads maiores / mais lentos sofrem mais com isso, então suspeito de um tempo limite. Eu tentei ler o erro 499: as conclusões parecem ser que é "conexão fechada do cliente". Esse poderia ser o caso em segundo plano, mas não tenho certeza de como isso significaria que uma segunda solicitação deveria ser emitida e certamente não há algo como "navegador fechado pelo usuário" acontecendo.

Atualmente, parece ajudar a dividir as solicitações POST mais lentas (se houver várias coisas para fazer, basta fazer com que o usuário escolha 1 e POST uma segunda vez para a outra), mas isso pode estar diminuindo a chance de ocorrer . Não tenho certeza.

Esta é obviamente uma solução temporária. Se é um tempo limite, eu preciso descobrir onde e aumentar os números correspondentes, mas não sei por que um tempo limite causaria esse comportamento: eu suspeitaria de um "bem, isso deu errado "mensagem, não uma repetição.

Perguntas

Estou procurando descobrir qual processo / situação pode fazer com que um POST seja repetido. Claro, qualquer "não sei porquê, mas será corrigido aumentando este timeout" também é ótimo.

configurações 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;
}

conf.d

Eu removi algumas linhas específicas de IP nas partes geo , bem como as variações SSL , para simplificar. Se necessário, posso substituí-los, mas isso se resume a uma parte geo extra para os back-ends ssl e correspondentes upstream e arquivos conf.

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;
    
por Nanne 15.07.2013 / 11:42

2 respostas

1

De este tópico do fórum , aprendemos que o culprint pode ser SPDY. Para esse usuário, parece uma solução para desativá-lo, e nós não tivemos postagens duplas desde que o desativamos.

O problema exato, outro então "SPDY o fez", é desconhecido neste momento, os efeitos colaterais da solução proposta (desabilitar SPDY) são obviamente "não há mais SPDY", mas podemos viver com isso.

Até que o bug pule de novo, eu chamo isso de 'correção' (ou pelo menos: uma solução para o problema).

edite: Nós não (25-02-2014) vimos este problema mais, então esta parece ser uma solução duradoura, de fato.

    
por 17.07.2013 / 14:29
2

Resposta curta: tente isto para o seu bloco de localização:

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

Explicação mais longa:

Acho que acabei de encontrar exatamente o problema que você descreveu:

  • Eu uso o proxy reverso nginx como balanceador de carga
  • para solicitações de longa execução, o back-end recebe a mesma solicitação várias vezes
  • os registros de acesso nginx dos nós de envio mostram 499 status para essas solicitações, e a mesma solicitação aparece em diferentes nós de envio

Acontece que este é, na verdade, o comportamento padrão do nginx como proxy reverso, e atualizá-lo para versões superiores, portanto, não resolverá esse problema, embora tenha sido fornecido como uma possível solução aqui , mas isso aborda um problema diferente.

Isso acontece porque o nginx como balanceador de carga escolhe um nó do upstream em moda round-robin . Quando o nó escolhido falha, o pedido é enviado para o próximo nó. O importante a ser observado aqui é que a falha do nó é, por padrão, classificada como error or timeout . Como você não definiu um proxy_read_timeout , o padrão é 60 segundos. Então, após 60 segundos de espera, o nginx escolhe o próximo nó e envia o mesmo pedido.

Portanto, uma solução é aumentar esse tempo limite para que sua operação de longa duração seja concluída, por exemplo, definindo proxy_read_timeout 120; (ou qualquer limite que atenda às suas necessidades).

Outra opção é impedir que o proxy reverso tente usar o próximo nó, no caso de tempo limite, configurando proxy_next_upstream error; . Ou você pode definir essas duas opções, conforme sugerido acima.

    
por 13.06.2016 / 14:27