WCF-Ermittlung über UDP verursacht hohe CPU-Auslastung und Netzwerküberlastung

Dieser Artikel hilft Ihnen, den Fehler zu beheben, der auftritt, wenn Sie Windows Communication Foundation (WCF)-Unterstützung für WS-Discovery über UDP verwenden.

Ursprüngliche Produktversion:   Windows Communication Foundation
Ursprüngliche KB-Nummer:   2777305

Problembeschreibung

Wenn Sie WCF-Unterstützung für WS-Discovery über UDP verwenden, werden möglicherweise eines oder mehrere der folgenden Probleme angezeigt:

  • Ein unerwarteter Anstieg der CPU-Auslastung auf dem Server.
  • Höher als erwarteter Multicast-Datenverkehr.
  • Unerwartet viele SOAP-Fehlermeldungen, die über das Netzwerk in einer Umgebung gesendet werden, in der .NET 4.5 installiert ist.

Das Problem kann auch auftreten, wenn der Dienst nicht für .NET 4.5 kompiliert wurde, sondern in einer Umgebung ausgeführt wird, in der .NET 4.5 installiert ist.

Ursache

Diese Probleme können aus den folgenden Gründen auftreten:

  1. Falsche Behandlung unerwarteter Nachrichtentypen auf einigen internen Infrastrukturendpunkten von WCF Discovery.

  2. Der WCF-Dienst hostet mehrere UDP-Multicastdienste, bei denen mehrere Dienste eine bestimmte Multicastadresse und einen bestimmten Port teilen.

Lösung

Um dieses Problem zu beheben, wenden Sie eines der Updates an, die in den folgenden Knowledge Base (KB)-Artikeln beschrieben sind:

Problemumgehung

Um diese Probleme zu umgehen, wählen Sie eine der folgenden Optionen aus:

  • Problemumgehung 1:

    Erzwingen Sie programmgesteuert die Verwendung des Duplexkanals anstelle des IReplyChannel in 4.5 eingeführten Kanals. Es folgt ein C#-Codebeispiel, um dies auf dienstseitiger Seite (auf dem Server) zu erreichen. Mithilfe der folgenden Klasse können wir eine benutzerdefinierte Implementierung haben, die CanBuildChannelListener "false" zurückgibt IReplyChannel für:

    class DisableIReplyChannelShapeBindingElement : BindingElement
    {
        public override BindingElement Clone()
        {
            return this;
        }
        public override T GetProperty<T>(BindingContext context)
        {
            return null;
        }
        public override bool CanBuildChannelListener<TChannel>(BindingContext context)
        {
            if (typeof(TChannel) == typeof(IReplyChannel))
            {
                return false;
            }
            return context.CanBuildInnerChannelListener<TChannel>();
        }
    }
    

    Durch Einfügen dieser Eigenschaft in die Bindung kann ihre Anwendung die Tatsache ausblenden, dass der UDP-Transport das IReplyChannel Shape von der announcementEndpoint unterstützt, wodurch das Problem vermieden wird. Nachfolgend finden Sie eine Hilfsmethode, die später verwendet wird:

    public static void DisableIReplyChannelShape(ServiceEndpoint endpoint)
    {
        CustomBinding customBinding = new CustomBinding(endpoint.Binding);
        //only do this if using the UdpTransport.
        if (customBinding.Elements.Find<UdpTransportBindingElement>()!= null)
        {
            customBinding.Elements.Insert(customBinding.Elements.Count - 1, new DisableIReplyChannelShapeBindingElement());
            endpoint.Binding = customBinding;
        }
    }
    

    Sie können verhindern, dass Ihr serverseitiger Code die Fehlermeldungen sendet, die Probleme verursachen, indem Sie Folgendes für Dies announcementEndpoint tun:

    UdpAnnouncementEndpoint announcementEndpoint = new UdpAnnouncementEndpoint();
    DisableIReplyChannelShape(announcementEndpoint);
    
  • Problemumgehung 2:

    Wenn Sie keinen Zugriff auf den serverseitigen Code haben, können Sie stattdessen Folgendes auf der Clientseite hinzufügen. Fügen Sie dieses Verhalten zu Ihrer clientseitigen UdpDiscoveryEndpoint hinzu. Diese Problemumgehung muss auf alle Discovery-Clients angewendet werden, unabhängig davon, ob sie in .NET 4.5 oder in .NET 4.0 kompiliert wurden.

    Hinweis

    Microsoft empfiehlt dringend Die Problemumgehung 1 (serverseitig), da dadurch verhindert wird, dass das Problem auf WCF- und Nicht-WCF-Discoveryclients auftritt. Problemumgehung 2 gilt nur für WCF-Clients.

    Der Clientcode:

    UdpDiscoveryEndpoint clientEndpoint = new UdpDiscoveryEndpoint();
    clientEndpoint.Behaviors.Add(new WorkaroundBehavior());
    var discoveryClient = new DiscoveryClient(clientEndpoint);
    

    Die Klasse:

    class WorkaroundBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            if (clientRuntime == null)
            {
                throw new ArgumentNullException("clientRuntime");
            }
            clientRuntime.CallbackDispatchRuntime.UnhandledDispatchOperation.Invoker = new UnhandledActionOperationInvoker();
        }
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }
        public void Validate(ServiceEndpoint endpoint)
        {
        }
        class UnhandledActionOperationInvoker : IOperationInvoker
        {
            public bool IsSynchronous
            {
                get
                {
                    return true;
                }
            }
            public object[] AllocateInputs()
            {
                return new object[1];
            }
            public object Invoke(object instance, object[] inputs, out object[] outputs)
            {
                outputs = new object[0];
                return Message.CreateMessage(MessageVersion.None, string.Empty);
            }
            public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
            {
                throw new NotImplementedException();
            }
            public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
            {
                throw new NotImplementedException();
            }
        }
    }
    
  • Problemumgehung 3:

    Verwenden Sie eine eindeutige Multicastadresse und/oder einen eindeutigen Port für jeden Dienst, der das SOAP.UDP Protokoll überwacht.