Rake sur le chemin de la survie

L'augmentation de l'activité d'échange de données entre microservices est souvent un problème dans l'architecture des solutions informatiques modernes. Pressez le maximum et survivez à tout prix - un défi sérieux pour tout développement. Par conséquent, la recherche de solutions optimales est un processus continu. L'article décrit brièvement les problèmes pouvant survenir lors de l'utilisation de requêtes http très chargées et les moyens de les contourner.


Cette histoire commence par une erreur. D'une manière ou d'une autre, nous avons effectué des tests de charge, dont l'élément principal était l'exécution d'un grand nombre de courtes requêtes http. Un client écrit sous netcore 2.2 , à partir d'un moment donné, lève une System.Net.Sockets.SocketException: adresse déjà utilisée . Il est rapidement devenu évident que les ports n'avaient pas eu le temps de libérer du client, et à un moment donné, le système a refusé d'en ouvrir un nouveau. Maintenant, si nous passons au code, le problème résidait dans l'utilisation de l'ancienne approche avec la classe et la construction HttpWebRequest :


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

Il semblerait que nous libérons la ressource, et le port devrait être libéré en temps opportun. Cependant, netstat a signalé une augmentation rapide du nombre de ports dans l'état TIME_WAIT. Cet état signifie attendre la fermeture de la connexion (et éventuellement recevoir des données perdues). Par conséquent, le port peut y rester pendant 1 à 2 minutes. Ce problème est traité en détail dans de nombreux articles ( Problèmes avec la file d'attente TIME_WAIT , Historique de TIME_WAIT ). Néanmoins, cela signifie que dotnet essaie «honnêtement» de fermer la connexion, et cela se produit déjà par la faute des paramètres de temporisation dans le système.


Pourquoi cela se produit-il et comment y faire face


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 - utilise la classe HttpWebRequest en mode "Connexion: fermée"

Le serveur nginx est configuré avec les paramètres suivants:


  • keepalive_timeout 60s;
  • keepalive_requests 100000;

MéthodeNLes pubsSignifier
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