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;