SignalRASP.NET Core Hosting und Skalierung

Von Andrew Prozentton-Nurse, Brady Gasterund Tom Dykstra

In diesem Artikel werden Überlegungen zum Hosten und Skalieren von Apps mit hohem Datenverkehr erläutert, die ASP.NET Core SignalR verwenden.

Sticky Sessions

SignalR erfordert, dass alle HTTP-Anforderungen für eine bestimmte Verbindung vom gleichen Serverprozess verarbeitet werden. Wenn SignalR auf einer Serverfarm (mehrere Server) ausgeführt wird, müssen "Sticky Sessions" verwendet werden. "Sticky Sessions" werden von einigen Load Balancern auch als Sitzungsaffinität bezeichnet. Azure App Service verwendet arr (Application Request Routing) zum Weiterleiten von Anforderungen. Wenn Sie die Einstellung "ARR-Affinität" in Ihrem Azure App Service aktivieren, werden "Sticky Sessions" aktiviert. Die einzigen Umstände, unter denen keine sticky-Sitzungen erforderlich sind, sind:

  1. Beim Hosten auf einem einzelnen Server in einem einzigen Prozess.
  2. Bei Verwendung des SignalR Azure-Diensts.
  3. Wenn alle Clients so konfiguriert sind, dass nur WebSockets verwendet werden, und die Einstellung SkipNegotiation in der Clientkonfiguration aktiviert ist.

Unter allen anderen Umständen (einschließlich der Verwendung der Redis-Backplane) muss die Serverumgebung für sitzungsbehaltene Sitzungen konfiguriert werden.

Anleitungen zum Konfigurieren von Azure App Service für SignalR finden Sie unter Veröffentlichen einer ASP.NET SignalR Core-App für Azure App Service . Anleitungen zum Konfigurieren von sitzungsbeendigen Sitzungen für Blazor Apps, die den SignalR Azure-Dienstverwenden, finden Sie unter Hosten und Bereitstellen von ASP.NET Core Blazor Server .

TCP-Verbindungsressourcen

Die Anzahl gleichzeitiger TCP-Verbindungen, die ein Webserver unterstützen kann, ist begrenzt. Http-Standardclients verwenden kurzlebige Verbindungen. Diese Verbindungen können geschlossen werden, wenn der Client in den Leerlauf wechselt und später erneut geöffnet wird. Andererseits ist eine SignalR Verbindung persistent. SignalR -Verbindungen bleiben auch dann geöffnet, wenn der Client in den Leerlauf wechselt. In einer App mit hohem Datenverkehr, die viele Clients bedient, können diese permanenten Verbindungen dazu führen, dass Server ihre maximale Anzahl von Verbindungen erreichen.

Persistente Verbindungen verbrauchen auch zusätzlichen Arbeitsspeicher, um jede Verbindung nachzuverfolgen.

Die starke Nutzung verbindungsbezogener Ressourcen durch SignalR kann sich auf andere Web-Apps auswirken, die auf demselben Server gehostet werden. Wenn SignalR geöffnet wird und die letzten verfügbaren TCP-Verbindungen enthält, stehen anderen Web-Apps auf demselben Server auch keine weiteren Verbindungen zur Verfügung.

Wenn auf einem Server keine Verbindungen mehr vorhanden sind, werden zufällige Socketfehler und Fehler beim Zurücksetzen der Verbindung angezeigt. Beispiel:

An attempt was made to access a socket in a way forbidden by its access permissions...

Um zu vermeiden, dass die SignalR Ressourcennutzung Fehler in anderen Web-Apps verursacht, führen Sie SignalR auf anderen Servern als Ihre anderen Web-Apps aus.

Um zu vermeiden, dass die SignalR Ressourcennutzung Fehler in einer SignalR App verursacht, skalieren Sie auf, um die Anzahl der Verbindungen einzuschränken, die ein Server verarbeiten muss.

Aufskalieren

Eine App, die SignalR verwendet, muss alle verbindungen nachverfolgen, was zu Problemen für eine Serverfarm führt. Fügen Sie einen Server hinzu, und es werden neue Verbindungen hergestellt, die den anderen Servern nicht bekannt sind. Auf jedem Server im folgenden Diagramm sind beispielsweise SignalR die Verbindungen auf den anderen Servern nicht bekannt. Wenn SignalR auf einem der Server eine Nachricht an alle Clients senden möchte, wird die Nachricht nur an die Clients gesendet, die mit diesem Server verbunden sind.

Skalierung SignalR ohne Backplane

Die Optionen zum Lösen dieses Problems sind der SignalR Azure-Dienst und die Redis-Backplane.

Azure SignalR Service

Der SignalR Azure-Dienst fungiert als Proxy für Echtzeitdatenverkehr und verdoppelt sich als Backplane, wenn die App auf mehrere Server hochskaliert wird. Jedes Mal, wenn ein Client eine Verbindung mit dem Server initiiert, wird der Client umgeleitet, um eine Verbindung mit dem Dienst herzustellen. Der Prozess wird im folgenden Diagramm veranschaulicht:

Herstellen einer Verbindung mit dem Azure SignalR Dienst

Das Ergebnis ist, dass der Dienst alle Clientverbindungen verwaltet, während jeder Server nur eine kleine konstante Anzahl von Verbindungen mit dem Dienst benötigt, wie im folgenden Diagramm dargestellt:

Clients, die mit dem Dienst verbunden sind, Server, die mit dem Dienst verbunden sind

Dieser Ansatz für das aufskalieren hat gegenüber der Redis-Backplane-Alternative mehrere Vorteile:

  • Sticky-Sitzungen, auch als Clientaffinitätbezeichnet, sind nicht erforderlich, da Clients sofort an den Azure-Dienst umgeleitet SignalR werden, wenn sie eine Verbindung herstellen.
  • Eine SignalR App kann basierend auf der Anzahl der gesendeten Nachrichten aufskaliert werden, während der SignalR Azure-Dienst skaliert wird, um eine beliebige Anzahl von Verbindungen zu verarbeiten. Beispielsweise kann es Tausende von Clients geben, aber wenn nur wenige Nachrichten pro Sekunde gesendet werden, muss die SignalR App nicht auf mehrere Server aufskaliert werden, nur um die Verbindungen selbst zu verarbeiten.
  • Eine SignalR App verwendet nicht wesentlich mehr Verbindungsressourcen als eine Web-App ohne SignalR .

Aus diesen Gründen empfehlen wir den SignalR Azure-Dienst für alle in SignalR Azure gehosteten ASP.NET Core-Apps, einschließlich App Service, VMs und Containern.

Weitere Informationen finden Sie in der Dokumentation zum SignalR Azure-Dienst.

Redis-Backplane

Redis ist ein Schlüssel-Wert-Speicher im Arbeitsspeicher, der ein Messagingsystem mit einem Veröffentlichungs-/Abonnementmodell unterstützt. Die SignalR Redis-Backplane verwendet das Feature pub/sub, um Nachrichten an andere Server weiterzuleiten. Wenn ein Client eine Verbindung hergestellt, werden die Verbindungsinformationen an die Backplane übergeben. Wenn ein Server eine Nachricht an alle Clients senden möchte, wird er an die Backplane gesendet. Die Backplane kennt alle verbundenen Clients und die Server, auf denen sie sich befinden. Die Nachricht wird über die jeweiligen Server an alle Clients gesendet. Dieser Prozess wird im folgenden Diagramm veranschaulicht:

Redis-Backplane, Nachricht, die von einem Server an alle Clients gesendet wird

Die Redis-Backplane ist der empfohlene Ansatz für die aufskalierende Skalierung für Apps, die in Ihrer eigenen Infrastruktur gehostet werden. Wenn zwischen Ihrem Rechenzentrum und einem Azure-Rechenzentrum eine erhebliche Verbindungslatenz besteht, ist Der SignalR Azure-Dienst möglicherweise keine praktische Option für lokale Apps mit geringer Latenz oder hohen Durchsatzanforderungen.

Die SignalR oben erwähnten Azure-Dienstvorteile sind Nachteile für die Redis-Backplane:

  • Sticky-Sitzungen, die auch als Clientaffinitätbezeichnet werden, sind erforderlich, es sei denn, die beiden folgenden Sind wahr:
    • Alle Clients sind so konfiguriert, dass sie nur WebSockets verwenden.
    • Die Einstellung SkipNegotiation ist in der Clientkonfiguration aktiviert. Sobald eine Verbindung auf einem Server initiiert wurde, muss die Verbindung auf diesem Server verbleiben.
  • Eine SignalR App muss basierend auf der Anzahl der Clients aufskaliert werden, auch wenn nur wenige Nachrichten gesendet werden.
  • Eine SignalR App verwendet deutlich mehr Verbindungsressourcen als eine Web-App ohne SignalR .

IIS-Einschränkungen für Windows Clientbetriebssystem

Windows 10 und Windows 8.x sind Clientbetriebssysteme. IIS auf Clientbetriebssystemen hat einen Grenzwert von 10 gleichzeitigen Verbindungen. SignalRDie Verbindungen von sind:

  • Vorübergehend und häufig wieder hergestellt.
  • Wird nicht sofort verworfen, wenn sie nicht mehr verwendet wird.

Die oben genannten Bedingungen machen es wahrscheinlich, dass das Verbindungslimit von 10 auf einem Clientbetriebssystem erreicht wird. Wenn ein Clientbetriebssystem für die Entwicklung verwendet wird, wird Folgendes empfohlen:

  • Vermeiden Sie IIS.
  • Verwenden Sie Kestrel oder IIS Express als Bereitstellungsziele.

Linux mit Nginx

Im Folgenden sind die mindestens erforderlichen Einstellungen zum Aktivieren von WebSockets, ServerSentEvents und LongPolling für SignalR enthalten:

http {
  map $http_connection $connection_upgrade {
    "~*Upgrade" $http_connection;
    default keep-alive;
}

  server {
    listen 80;
    server_name example.com *.example.com;

    # Configure the SignalR Endpoint
    location /hubroute {
      # App server url
      proxy_pass http://localhost:5000;

      # Configuration for WebSockets
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_cache off;
      # WebSockets were implemented after http/1.0
      proxy_http_version 1.1;

      # Configuration for ServerSentEvents
      proxy_buffering off;

      # Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
      proxy_read_timeout 100s;

      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }
}

Wenn mehrere Back-End-Server verwendet werden, müssen sticky-Sitzungen hinzugefügt werden, um zu verhindern, dass SignalR Verbindungen beim Herstellen einer Verbindung zwischen Servern wechseln. Es gibt mehrere Möglichkeiten, sticky sessions in Nginx hinzuzufügen. Je nachdem, was Sie zur Verfügung haben, werden unten zwei Ansätze gezeigt.

Zusätzlich zur vorherigen Konfiguration wird Folgendes hinzugefügt. In den folgenden Beispielen backend ist der Name der Gruppe von Servern.

Verwenden Sie mit Nginx Open Source, um Verbindungen mit einem Server basierend auf der ip_hash IP-Adresse des Clients weiterzuleiten:

http {
  upstream backend {
    # App server 1
    server localhost:5000;
    # App server 2
    server localhost:5002;

    ip_hash;
  }
}

Verwenden Sie mit Nginx Plus, sticky um eine zu Anforderungen hinzuzufügen und die Anforderungen des Benutzers an einen Server cookie anzuheften:

http {
  upstream backend {
    # App server 1
    server localhost:5000;
    # App server 2
    server localhost:5002;

    sticky cookie srv_id expires=max domain=.example.com path=/ httponly;
  }
}

Ändern Sie abschließend proxy_pass http://localhost:5000 im server Abschnitt in proxy_pass http://backend .

Weitere Informationen zu WebSockets über Nginx finden Sie unter NGINX als WebSocket-Proxy.

Weitere Informationen zum Lastenausgleich und zu sitzungsbehaltenen Sitzungen finden Sie unter NGINX-Lastenausgleich.

Weitere Informationen zu ASP.NET Core mit Nginx finden Sie im folgenden Artikel:

SignalRBackplane-Anbieter von Drittanbietern

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Ressourcen: