Rastrillo en el camino para mantenerse vivo

Aumentar la actividad de intercambio de datos entre microservicios es a menudo un problema en la arquitectura de las soluciones de TI modernas. Exprime al máximo y sobrevive a toda costa, un desafío serio para cualquier desarrollo. Por lo tanto, la búsqueda de soluciones óptimas es un proceso continuo. El artículo describe brevemente los problemas que pueden surgir al usar solicitudes http altamente cargadas y las formas de evitarlas.


Esta historia comienza con un error. De alguna manera llevamos a cabo pruebas de carga, cuyo elemento principal fue la ejecución de una gran cantidad de solicitudes http cortas. Un cliente escrito en netcore 2.2 , comenzando en algún momento, arroja un System.Net.Sockets.SocketException: dirección ya en uso . Rápidamente se hizo evidente que los puertos no tenían tiempo para liberar al cliente, y en algún momento el sistema se negó a abrir uno nuevo. Ahora, si vamos al código, el problema estaba en usar el viejo enfoque con la clase HttpWebRequest y la construcción:


var request = WebRequest.CreateHttp(uri);
using(var resp = request.GetResponse()){ … }

Parece que estamos liberando el recurso, y el puerto debería liberarse de manera oportuna. Sin embargo, netstat señaló un rápido aumento en el número de puertos en estado TIME_WAIT. Este estado significa esperar a que se cierre la conexión (y posiblemente recibir datos perdidos). Como resultado, el puerto puede estar en él durante 1-2 minutos. Este problema se analiza con cierto detalle en muchos artículos ( Problemas con la cola TIME_WAIT , Historial sobre TIME_WAIT ). Sin embargo, esto significa que dotnet está tratando "honestamente" de cerrar la conexión, y ya pasa por la falla de la configuración del tiempo de espera en el sistema.


¿Por qué sucede esto y cómo lidiar con eso?


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: utiliza la clase HttpWebRequest modo "Conexión: cerrada"

El servidor nginx está configurado con los siguientes parámetros:


  • keepalive_timeout 60s;
  • keepalive_requests 100000;

MétodonorteLos anunciosMedia
Runhttpclient10001963,3 ms
RunWebRequestClosed100013.857,4 ms
RunHttpClientClosed100011,612.4 ms
Runhttpclient10,00019,573.9 ms
RunWebRequestClosed10,000137,947.4 ms
RunHttpClientClosed10,000116,112.9 ms

All Articles