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;