
Na documentação do Nginx existem diretivas referentes a três tempos limite diferentes, que podem ser configurados para servidores "backend" da seguinte forma:
proxy_connect_timeout
Define um tempo limite para estabelecer uma conexão com um servidor proxy. Deve-se observar que esse tempo limite geralmente não pode exceder 75 segundos.
Isso é fácil de entender - o Nginx está prestes a se conectar a um servidor "backend" upstream e, se não conseguir se conectar dentro de um período de tempo X, ele desistirá e retornará um erro. O servidor está inacessível, tem muitas conexões, etc.
proxy_read_timeout
Define um tempo limite para leitura de uma resposta do servidor proxy. O tempo limite é definido apenas entre duas operações de leitura sucessivas e não para a transmissão de toda a resposta. Se o servidor proxy não transmitir nada nesse período, a conexão será encerrada.
Isso também faz sentido - o Nginx já estabeleceu uma conexão TCP com o servidor "backend" e agora está prestes a enviar a solicitação, mas o servidor está demorando muito para processar e se demorar mais do que X tempo, feche a conexão e retornar ao usuário.
Na verdade, fiquei surpreso que o Nginx fechasse a conexão. Achei que manteria a conexão, mas retornaria um erro ao usuário. Parece caro restabelecer essas conexões TCP de "back-end" sempre que algo expira.
proxy_send_timeout
Define um tempo limite para transmitir uma solicitação ao servidor proxy. O tempo limite é definido apenas entre duas operações de gravação sucessivas, e não para a transmissão de toda a solicitação. Se o servidor proxy não receber nada nesse período, a conexão será encerrada.
Este eu não entendo muito bem. Eu tenho uma teoria, mas quero que alguém a confirme. O único valor que consigo pensar para esse tempo limite é se a carga útil da solicitação for enorme (por exemplo, grande solicitação POST com JSON ou documento que o usuário deseja salvar). A transmissão da solicitação para o "backend" exigirá a divisão da solicitação em segmentos TCP MTU menores e o envio deles como "pedaços" da solicitação original. Então, tecnicamente, não enviamos a solicitação até transmitirmos todos os pedaços ao servidor com êxito. O Nginx está medindo o tempo entre cada parte da solicitação? É isso que "escrever" significa no documento? Assim que a solicitação for realmente enviada, o Nginx começará a medir o proxy_read_timeout
?
Responder1
TCP/IP é o chamado protocolo de transmissão de dados "streaming". Ele foi projetado para permitir que a parte que lê dados em uma conexão TCP/IP não precise necessariamente se preocupar com tamanhos de "segmentos" ou mesmo pacotes. Isto se traduz, na prática, em uma situação em que um peer invoca alguma operação tradicional de "leitura" para obter dados enviados pelo peer remoto (por exemplo,read
com Linux), não lerá necessariamente de uma só vez exatamente a mesma quantidade de dados que a extremidade remota forneceu para uma única operação de "gravação". A implementação do protocolo TCP/IP invariavelmente criará pacotes IP de tamanho apropriado a partir do que foi passado para uma operação de "gravação" de cada vez, e a implementação na outra extremidade reunirá os dados desses pacotes; mas não vainecessariamente entregue-os a algum aplicativo cliente de "leitura" com os mesmos limites de dados!
Exemplo: A tem 50Kb de dados para enviar para cada evento externo do sistema, tanto que eles não cabem na RAM todos ao mesmo tempo, então eles os enviam em pedaços de 16Kb que é o tamanho do buffer de envio. Então eles enviam primeiro 16Kb, depois mais 16Kb, depois mais 16Kb e finalmente 2Kb. A implementação do TCP/IP pode enviar esses 50Kb, armazenados internamente em um buffer de 128Kb (por exemplo, um buffer de kernel), e só então enviá-los pela rede, que também tem suas próprias condições. Alguns desses dados, fragmentados de uma forma que o aplicativo remetente nem percebe, chegam primeiro ao outro extremo - devido às condições da rede - e são montados pela implementação TCP/IP e colocados em um buffer do kernel de novo. O kernel ativa o processo que deseja ler os dados – lendo todos os 30 KB deles. O receptor deve decidir se espera mais e como entender quanto mais esperar - oformatarda "mensagem" ou dos dados não é algo que preocupa o TCP/IP.
Isso significa que o Nginx não pode saber quanto da solicitação de um cliente ele lerá de uma vez para cada read
chamada que fará em um sistema baseado em Linux, por exemplo.
A documentação de proxy_send_timeout
algumas dicas sobre para que serve (ênfase minha), no entanto:
Define um tempo limite para transmitir uma solicitação ao servidor proxy. O tempo limite é definido apenas entre duas operações de gravação sucessivas, e não para a transmissão de toda a solicitação.Se o servidor proxy não receber nada dentro deste período, a conexão será fechada.
O problema é que, já que o Nginxprocuradoresuma solicitação - o que significa que a solicitação nãooriginarcom ele - ele espera que o cliente "downstream" (a extremidade remota da conexão que enviou a solicitação ao Nginx que este último em sua função de "proxy" agora espera encaminhar o upstream) transmita os dados da solicitação antes dele encaminha (grava) pela conexão upstream.
Pelo que entendi, se não houver nada recebido do downstream [durante o período de tempo limite], o servidor proxy também não receberá nada - e a conexão será encerrada.
Dito de outra forma, se o referido downstream não enviar nada dentro do período indicado por proxy_send_timeout
, o Nginx fechará a conexão com o upstream.
Por exemplo, considere um navegador da Web que envia uma solicitação ao Nginx. A primeira parte é lida pelo Nginx no tempo A. Supondo que ele fará proxy da solicitação para algum upstream, ele abre uma conexão com esse upstream e transmite (grava) o que recebeu do navegador, através do soquete de conexão upstream. Em seguida, ele simplesmente espera que mais partes dos dados da solicitação sejam lidas no navegador - se a próxima parte não chegar após algum tempo limite X em relação ao tempo A, ele fechará a conexão com o upstream.
Lembre-se de que isso não significa necessariamente que a conexão com o navegador da Web será fechada - certamente retornará algum código de status de erro HTTP para a solicitação, mas o tempo de vida da conexão do navegador da Web é governado por um conjunto de condições diferente do que proxy_send_timeout
- o o último diz respeito apenas às conexões do Nginx com o upstream.