1
votes

Erreur inattendue sur ReliableSession dans NetTcpBinding (WCF)

J'ai une application client-serveur. Mon scénario:

  • .Net Framework 4.6.1
  • Machine Quad Core i7 avec hyperthreading activé
  • Charge du processeur du serveur de 20 à 70%
  • Charge réseau
  • 100 utilisateurs
  • 30 services (certains administratifs, certains génériques par type de données) en cours d'exécution et chaque utilisateur est connecté à tous les services
  • NetTcpBinding (compression activée)
  • ReliableSession activé
  • chaque seconde, je déclenche (côté serveur) une notification de mise à jour et tous les clients se chargent depuis le serveur env. 100 Ko
  • De plus, un battement de cœur est en cours d'exécution (pour tester l'intervalle de 15 secondes) qui renvoie simplement l'heure du serveur en UTC

Parfois, les connexions WCF passent à l'état défectueux. Habituellement, lorsque cela se produit, le serveur n'a aucun réseau en amont. J'ai écrit un vidage de la mémoire et j'ai pu voir que beaucoup de threads WCF attendaient des WaitQueue . La pile d'appels est:

Server stack trace: 
   at System.ServiceModel.Channels.TransmissionStrategy.WaitQueueAdder.Wait(TimeSpan timeout)
   at System.ServiceModel.Channels.TransmissionStrategy.InternalAdd(Message message, Boolean isLast, TimeSpan timeout, Object state, MessageAttemptInfo& attemptInfo)
   at System.ServiceModel.Channels.ReliableOutputConnection.InternalAddMessage(Message message, TimeSpan timeout, Object state, Boolean isLast)
   at System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnSend(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.DuplexChannel.Send(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.DuplexChannelBinder.Send(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

J'ai modifié les paramètres et il semble que la situation s'est améliorée - Maintenant, il y a moins de clients en défaut. Mes paramètres:

  • ReliableSession.InactivityTimeout: 01:30:00
  • ReliableSession.Enabled: True
  • ReliableSession.Ordered: False
  • ReliableSession.FlowControlEnabled: False
  • ReliableSession.MaxTransferWindowSize: 4096
  • ReliableSession.MaxPendingChannels: 16384
  • MaxReceivedMessageSize: 1073741824
  • ReaderQuotas.MaxStringContentLength: 8388608
  • ReaderQuotas.MaxArrayLength: 1073741824

Je suis coincé. Pourquoi tous les appels essaient-ils d'attendre quelques WaitQueue dans la TransmissionStrategy ? Je ne me soucie pas des messages envoyés dans le désordre (je m'en occupe moi-même). Je pensais déjà à désactiver la messagerie fiable mais l'application est utilisée dans un réseau d'entreprise dans le monde entier. J'ai besoin de savoir que mes messages ont été livrés.

Des idées comment apprendre à WCF à simplement envoyer les messages sans se soucier de rien d'autre?

MODIFIER strong >

Les valeurs de limitation de service sont définies sur Int32.MaxValue.

J'ai également essayé de définir MaxConnections et ListenBackLog (sur NetTcpBinding ) à leurs valeurs maximales. Cela n'a rien changé - pour autant que je sache.

EDIT 2

Vérification des traces WCF qu'il me dit (message allemand, donc un translation) qu'il n'y a pas d'espace disponible dans la fenêtre de transfert de messagerie fiable - et alors tout ce que je reçois, ce sont des délais d'attente car plus aucun message n'est envoyé.

Que se passe-t-il là-bas? Est-il possible que les messages fiables se confondent?


8 commentaires

L'activation de la trace doit indiquer quand un canal est défaillant et pourquoi. Je pense qu'il vaut mieux donner une chance à la trace avant de bricoler une application de production


@Menahem veuillez vérifier Modifier 2


Cela ressemble à un problème plus profond, si la fenêtre de transfert 4096 est suffisante. Ses apparences ne sont pas reconnues. Le client et le serveur sont-ils sur le même réseau? Si c'est le cas, des sessions fiables ne sont pas nécessaires. Sinon peut-être que les accusés sont tombés


@Menahem dans mon environnement de test, la plupart d'entre eux sont sur le même commutateur - mais en production, il s'agit d'un réseau d'entreprise mondial


Et le problème est sur le net de test?


@Menahem J'ai mis en place cet environnement de test car j'ai ce comportement en production


Et ce problème se reproduit dans le test env?


continuons cette discussion dans le chat .


3 Réponses :


2
votes

La file d'attente peut être liée au comportement de limitation intégré de wcf https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/servicethrottling Le meilleur moyen de dépanner est d'activer le traçage WCF https://docs.microsoft. com / fr-fr / dotnet / framework / configure-apps / file-schema / wcf / servicethrottling Et sachez exactement quelle en est la cause


2 commentaires

Nan. Je les ai tous définis sur Int.MaxValue


Le traçage me dit simplement que la fenêtre de transfert fiable est pleine (voir ma question mise à jour). D'autres idées?



1
votes

Utilisez-vous connectionManagement pour définir maxconnection de votre client? (Si votre session est en duplex) https: //docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings

Votre MaxPendingChannels est défini sur 16384, ce qui rendra trop de clients attendent dans la file d'attente, si le serveur ne peut pas traiter les clients à temps, le canal peut passer à l'état d'erreur.

FlowControlEnabled signifie s'il faut continuer d'envoyer un message au serveur lorsque le serveur a pas d'espace libre pour enregistrer le message. Vous feriez mieux de le définir sur true.

InactivityTimeout signifie s'il faut fermer la session lorsqu'il n'y a pas d'échange de messages dans un certain laps de temps. Vous feriez mieux de le définir sur une valeur appropriée.

De plus, avez-vous défini le délai d'expiration de votre liaison?

  <netTcpBinding>
    <binding  closeTimeout="" openTimeout="" receiveTimeout="" sendTimeout="" ></binding>
  </netTcpBinding>


1 commentaires

J'utilise des valeurs par défaut, sauf pour le délai de réception.



1
votes

En bref:

Il s'avère que mes paramètres WCF sont très bien.

Le ThreadPool est le facteur limitant. Dans les situations de trafic élevé (et donc de forte charge), je génère trop de messages qui doivent être envoyés aux clients. Ceux-ci sont mis en file d'attente car il n'y a pas assez de threads de travail pour envoyer les messages. À un moment donné, la file d'attente est pleine - et vous y êtes.

Pour plus de détails, consultez cette question et réponse a> de Russ Bishop.

Détail intéressant: cela a même réduit la charge du processeur dans les situations de trafic élevé. De la pointe folle entre 30 et 80% à une valeur (n) (presque) stable d'environ 30%. Je ne peux que supposer que c'est à cause de la génération et du nettoyage des threads de threadpool.

MODIFIER

J'ai fait ce qui suit:

ThreadPool.SetMinThreads(1000, 500)

Ces valeurs pourraient être comme utiliser une masse pour casser une noix - mais cela fonctionne.


3 commentaires

Merci pour la mise à jour ! Mais qu'avez-vous fait pour résoudre le problème?


De plus, si le serveur appelle les clients uniquement en guise de notification, cela ne devrait pas prendre longtemps à gérer et ne drainera donc pas les ressources du serveur. il me semble que les appels à distance doivent être aussi courts que possible


@Menahem Pour clarifier davantage: lorsqu'un dataobject est modifié une notification de mise à jour est envoyée aux clients qui chargent alors la nouvelle version de l'objet. S'il y avait de nombreuses mises à jour, il semble que les threads de travail n'aient pas été en mesure de suivre le rythme ...