What is the possible explanation for this case?
Uma condição de corrida entre um contador inativo de ~ 5 segundos na origem e uma atividade variável no lado do cliente. A terceira variável envolvida é, obviamente, a latência da rede.
Parece haver um temporizador ocioso de ~ 5 segundos na origem, enquanto seu cliente leva ~ 5 segundos para fazer uma segunda solicitação (POST) através do proxy Nginx. Se o primeiro for maior que o último (incluindo latência de rede), você não terá problemas. Se demorar um pouquinho mais para o pedido do cliente ser enviado, você tem um problema.
Você pode ver como tanto o POST quanto o FIN, ACK do Nginx são enviados praticamente juntos: 2.4ms e 2.6ms após FIN e ACK da origem, respectivamente. Isso poderia te colocar fora do rumo aqui, porque eu não acho que o POST seja uma resposta ao FIN, ACK da origem. Como é enviado 2,4ms após FIN da origem, ACK
Why is the proxy (nginx) sending another request if it already received a FIN and is actually acknowledging it! (the ack number in the POST [PSH, ACK] packet is actually SEQ_NUMBER + 1 of the [FIN,ACK] - so it's acknowledging the phantom bit FIN.
O número ACK no pacote POST é provavelmente o pacote "200 OK". Não há dados extras vindo do lado do servidor após essa resposta HTTP, portanto, qualquer ACK do cliente será ACKING o mesmo número.
Atualização: Agora sabemos que o pacote POST tem o número ACK aumentado em 1, então Nginx sabia sobre [FIN, ACK]. Investigações posteriores mostram que está tudo bem: uma máquina pode enviar uma solicitação e terminar com um [FIN, ACK] se não estiver planejando continuar a conexão depois de receber a resposta do lado remoto, que deveria enviar os dados solicitados de volta e terminar. com a continuação do processo [FIN, ACK].
Isso não muda o fato de que há uma condição de corrida em que a origem decidiu fechar a conexão após 5 segundos ociosa, ignorando assim o pacote POST que vem logo após (e até mesmo enviando um RST de volta - embora não esteja claro se este RST teria sido enviado independentemente).
What are the possible reasons for the origin returning a [FIN,ACK] only after 5 seconds and not immediatelly? Read-timeout / idle-timeout?
Você não precisa retornar um FIN, ACK imediatamente, especialmente desde o HTTP 1.1 e a introdução de conexões persistentes. Estes ~ 5 segundos parecem ser um temporizador ocioso na origem.
As duas coisas são confirmadas aqui: link - incluindo um tempo limite ocioso padrão de 5 segundos no Apache 2.2 ou mais recente.
Soluções sugeridas
Eu não posso realmente sugerir uma solução sem saber mais sobre sua infraestrutura, mas em termos gerais você tem algumas opções:
- Investigue por que o cliente leva 5 segundos para enviar uma segunda solicitação. Desvantagens: demorado e, provavelmente, implica mudanças na aplicação.
- Aumenta o tempo limite da origem (Apache?) para talvez 10 segundos. Inconvenientes: Problemas para dimensionar à medida que você mantém mais recursos ociosos. Pode precisar de alterações na aplicação para descartar as conexões o mais rápido possível.
- Não reutilize a conexão TCP para uma segunda solicitação HTTP, emitindo o cabeçalho "Conexão: Fechar". Desvantagens: Maior custo por solicitação, pois você deve estabelecer uma nova sessão TCP. Pode implicar alterações no aplicativo para emitir o cabeçalho em todas as solicitações ou alterações no Nginx, desviando-se da configuração padrão (custos administrativos aumentados).
- Use a opção "keepalive" no Nginx dentro de sua configuração upstream para definir um keepalive menor que 5 segundos. Inconveniente: muito tráfego / ruído extra.
Espero que isso ajude:)