Comment puis-je prévenir la Prise/Port d'Épuisement?
Je tente de test de performance d'un site web, en la frappant avec les requêtes sur plusieurs threads. Chaque thread exécute n fois. (dans une boucle for)
Cependant, je suis en cours d'exécution dans des problèmes. Plus précisément le WebException ("Impossible de se connecter au serveur distant"), à l'exception interne:
Une opération sur un socket n'a pas pu être effectuée parce que le système
n'avait pas suffisamment d'espace tampon ou à cause d'une file d'attente était pleine
127.0.0.1:52395
Je suis de la tentative d'exécution des threads 100 à 500 itérations par thread.
D'abord j'ai été en utilisant HttpWebRequest
dans System.Net pour faire la requête GET au serveur. Actuellement, je suis en utilisant WebClient
comme je l'ai supposé que chaque itération a été à l'aide d'un nouveau socket (donc 100 * 500 logements dans un court laps de temps). Je suppose WebClient (qui est instancié qu'une seule fois par sujet) serait d'utiliser uniquement un support.
Je n'ai pas besoin de 50 000 sockets ouverts à la fois, que je voudrais vous envoyer la demande, de recevoir la réponse, et fermer le socket, libérant ainsi de l'utiliser dans la prochaine itération de boucle. Je comprends que ce serait un problème pour
Cependant, même avec WebClient, un tas de sockets sont demandés résultant en un tas de prises en TIME_WAIT
mode (vérifiée à l'aide de la commande netstat). Cela entraîne d'autres applications (comme les navigateurs internet) à se bloquer et cesser de fonctionner.
Je peux utiliser mon test avec moins d'itérations et/ou moins de fils, comme il semble que les sockets finalement le faire sortir de cet état TIME_WAIT. Cependant, ce n'est pas une solution car il n'a pas suffisamment tester les capacités du serveur web.
Question:
Comment puis-je fermer explicitement une prise (côté client) après chaque thread itération afin de prévenir TIME_WAIT unis et de la prise d'épuisement?
Code:
Classe qui encapsule le HttpRequest
Edit: Enveloppé WebClient dans une aide, une nouvelle est instancié,utilisés et éliminés pour chaque itération. Le problème persiste encore.
public sealed class HttpGetTest : ITest {
private readonly string m_url;
public HttpGetTest( string url ) {
m_url = url;
}
void ITest.Execute() {
using (WebClient webClient = new WebClient()){
using( Stream stream = webClient.OpenRead( m_url ) ) {
}
}
}
}
La partie de mon ThreadWrapperClass qui crée un nouveau thread:
public void Execute() {
Action Hammer = () => {
for( int i = 1; i <= m_iterations; i++ ) {
//Where m_test is an ITest injected through constructor
m_test.Execute();
}
};
ThreadStart work = delegate {
Hammer();
};
Thread thread = new Thread( work );
thread.Start();
}
Gardez à l'esprit il ya seulement environ 65000 ports disponibles, et pas tous d'entre eux peuvent être utilisés pour les connexions sortantes. Si vous devez utiliser plusieurs adresses ip/Nic pour faire de 50000 connexions que vous essayez de faire
Je comprends que ce serait un problème si j'ai été l'exécution d'un grand nombre de fils, cependant, une fois une itération de la boucle se fait que je n'ai pas le support le plus, mais il colle autour, provoquant la prochaine itération d'ouvrir un nouveau. Je suis à la recherche pour trouver un moyen d'empêcher ça
Vous faites une utilisation sur le stream que vous obtenez de retour, mais pas votre client web. Vous pourriez essayer une instruction d'utilisation sur votre WebClient ainsi afin qu'il soit éliminé. Ou manuellement éliminer une fois que vous avez terminé la lecture.
OriginalL'auteur James | 2012-07-19
Vous devez vous connecter pour publier un commentaire.
Ne vous comprenez le but de TIME_WAIT? C'est une période au cours de laquelle il serait dangereux de réutiliser le port parce que la perte de paquets (qui ont été retransmis) de la transaction précédente peut encore être livrés à l'intérieur de cette période de temps.
Vous pourriez probablement ajuster vers le bas dans le registre quelque part, mais je me demande si c'est un bon prochaine étape.
Mon expérience de la création d'réaliste de la charge dans un environnement de test ont été très frustrant. Certainement l'exécution de votre charge-testeur de localhost est pas réaliste, et la plupart des tests de réseau, j'ai fait à l'aide de l' .net http api semblent exiger plus grunt dans le client que le serveur lui-même.
En tant que tel, il est préférable de passer à une deuxième machine à générer de la charge sur votre serveur... cependant domestique de l'équipement de routage est rarement à la hauteur de soutenir n'importe où près le nombre de connexions qui seraient causer toute sorte de charge sur un bien écrit, serveur d'application, donc vous devez maintenant mettre à jour votre routage/commutation de l'équipement ainsi!
Enfin, j'ai aussi eu quelques vraiment étrange et inattendue des problèmes de performances autour de la .net Http API du client. À la fin de la journée, ils utilisent tous HttpWebRequest faire le gros du travail. IMO c'est loin d'être aussi performant qu'il pourrait l'être. DNS est sychronous, même lors de l'appel de l'Api asynchrone (bien que si vous avez une requête à partir d'un seul hôte, ce n'est pas un problème), et après avoir soutenu l'utilisation de la CPU de l'utilisation de la rampe vers le haut jusqu'à ce que le client devient CPU contrainte plutôt que IO limitée. Si vous êtes à la recherche pour générer durable et de charge lourde, toute demande lourde de l'application dépend HttpWebRequest est de l'OMI, un bidon d'investissement.
Dans l'ensemble, une assez délicat travail, et, finalement, quelque chose qui ne peut être prouvé dans la nature, sauf si vous avez plently de l'argent à dépenser sur une armada de meilleurs équipements.
[Indice: j'ai eu beaucoup mieux les performances de mon propre client écrit en utilisant async Socket api et une 3ème partie client DNS de bibliothèque]
Eh bien, DNS ne va pas être un problème pour vous, mais vous pourriez trouver cela intéressant: stackoverflow.com/questions/11480742/... . J'ai trouvé, vous pouvez obtenir beaucoup de meilleures performances de bavarder HTTP à l'aide de l' .net api Socket. J'ai écrit une petite bibliothèque de moi-même (pour la recherche), mais ne peut pas le partager, car il appartient à mon entreprise, et il n'implémente un très sous-ensemble limité de HTTP. Il permet cependant .filet très rapide en effet lorsque vous faites HTTP, frapper IO limites alors que pratiquement au ralenti.
OriginalL'auteur
Un: Mec, TIME_WAIT est une partie intégrante et importante! - une partie de TCP/IP lui-même!
Vous peut tune le système d'exploitation afin de réduire TIME_WAIT (qui peut avoir des répercussions négatives).
Et vous pouvez ajuster le système d'exploitation pour accroître #/ports éphémères:
Voici un lien sur pourquoi TIME_WAIT existe ... et pourquoi c'est une Bonne Chose:
OriginalL'auteur
Il semble que vous n'êtes pas forcer votre WebClient pour se débarrasser des ressources qu'il a attribuées. Vous effectuez une Aide sur le flux de données retourné, mais votre WebClient a encore des ressources.
Soit l'enveloppe de votre WebClient instanciation dans un bloc using ou manuellement, à l'appel de jeter sur elle une fois que vous avez terminé la lecture à partir de l'URL.
Essayez ceci:
Je ne suis pas certain de ce que c'est alors, désolé, je ne pouvais pas avoir plus d'aide.
OriginalL'auteur
Ce n'est pas un problème de fermeture ou de sockets en libérant les ressources de votre application. Le TEMPS _WAIT est une pile TCP timeot publié sur les sockets pour empêcher leur utilisation jusqu'à ce qu'il est pratiquement impossible pour un paquets de 'gauche' à partir d'une précédente connexion au socket de ne pas avoir expiré.
À des fins de test, vous pouvez réduire le temps d'attente à partir de la valeur par défaut (de quelques minutes, autant que je sache), à une valeur inférieure. Lors de test de charge des serveurs, je l'ai mis moins de six secondes.
C'est dans le registre quelque part, vous les trouverez si vous Google.
Trouvé:
Changement TIME_WAIT retard
OriginalL'auteur
Vous n'avez pas besoin de se compliquer la vie avec TIME_WAIT pour accomplir ce que vous voulez.
Le problème est que vous vous débarrasser de la WebClient chaque fois que vous appelez Execute(). Lorsque vous faites cela, vous fermer la socket de connexion avec le serveur et le port TCP maintient occupé pour le TIME_WAIT période.
Une meilleure approche est de créer le client web dans le constructeur de votre HttpGetTest de classe et de réutiliser le même objet tout au long du test.
WebClient utilise garder en vie par défaut et de réutilisation de la même connexion pour l'ensemble de ses demandes, donc dans votre cas il n'y aura que 100 connexions ouvertes pour cette.
Hmm... la question a été édité, je n'ai pas vu le code original. 1. Oui, c'est exact, comme je l'ai dit. 2. Oui, même hôte, sinon comment pourrait-il être? Aussi, il n'a pas dit, il y avait de nombreux hôtes et même si c'était un webfarm, 100 threads serait probablement suffisant pour frapper tous les serveurs (en supposant que c'est de loin inférieur à 100). Il y a probablement autre chose, WebClient doit comporter correctement si vous le réutiliser. Et la question est "Comment puis-je prévenir la Prise/Port d'Épuisement?": à l'aide de WebClient (ou peut-être HttpClient) correctement permettra d'éviter le port de l'épuisement.
OriginalL'auteur