Aumentar a atividade de troca de dados entre microsserviços geralmente é um problema na arquitetura das soluções modernas de TI. Aperte o máximo e sobreviva a todo custo - um sério desafio para qualquer desenvolvimento. Portanto, a busca de soluções ideais é um processo ininterrupto. O artigo descreve brevemente os problemas que podem surgir ao usar solicitações HTTP altamente carregadas e maneiras de ignorá-las.
Esta história começa com um erro. De alguma forma, realizamos testes de carga, cujo principal elemento foi a execução de um grande número de solicitações curtas de http. Um cliente gravado no netcore 2.2 , iniciando em algum momento, lança um System.Net.Sockets.SocketException: Endereço já em uso . Logo ficou claro que as portas não tinham tempo para liberar o cliente e, em algum momento, o sistema foi recusado a abrir uma nova. Agora, se formos ao código, o problema estava no uso da abordagem antiga com a classe e construção HttpWebRequest :
var request = WebRequest.CreateHttp(uri);
using(var resp = request.GetResponse()){ … }
Parece que estamos liberando o recurso e a porta deve ser liberada em tempo hábil. No entanto, o netstat sinalizou um rápido aumento no número de portas no estado TIME_WAIT. Esse estado significa aguardar o fechamento da conexão (e possivelmente receber dados perdidos). Como resultado, a porta pode ficar nela por 1-2 minutos. Esse problema é discutido com mais detalhes em muitos artigos ( problemas com a fila TIME_WAIT , histórico sobre TIME_WAIT ). No entanto, isso significa que o dotnet está "honestamente" tentando fechar a conexão, e isso já acontece mais devido à falha das configurações de tempo limite no sistema.
Por que isso está acontecendo e como lidar com isso
keep-alive. . , . msdn, KeepAlive HttpWebRequest true. HttpWebRequest «» , , . , HttpWebRequest «Connection: keep-alive», HTTP/1.1. , , KeepAlive. HttpWebRequest.KeepAlive = false, «Connection: close». , . nginx .
:
while (true)
{
var request = WebRequest.CreateHttp(uri);
request.KeepAlive = false;
var resp = await request.GetResponseAsync();
using (var sr = new StreamReader(resp.GetResponseStream()))
{
var content = sr.ReadToEnd();
}
}
, ( 1000 ) . CLOSE_WAIT, LAST_ACK. - , . , «» .
,
, , . keep-alive HttpClient. .
, , ? keep-alive nginx:
- keepalive_timeout – ( 15)
- keepalive_requests – ( 100)
netstat wireshark, . keepalive_requests (> 1000) , .
http , . . , , keep-alive. keep-alive , .
:
- RunHttpClient – HttpClient "Connection: keep-alive"
- RunHttpClientClosed – HttpClient "Connection: closed"
- RunWebRequestClosed - usa o modo HttpWebRequest da classe "Connection: closed"
O servidor nginx está configurado com os seguintes parâmetros:
- keepalive_timeout 60s;
- keepalive_requests 100000;