SignalR In Load Balanced Environments

When load balancing the backoffice, we also need to take care of the client-to-server communication outside of web requests. Umbraco uses SignalR to abstract away these types of communication. This also allows us to support load balancing by replacing how the communication is done by introducing a backplane.

Understanding SignalR Backplanes

A traditional SignalR backplane (such as SQL Server or Redis) distributes messages between servers. Any server can broadcast messages to clients connected to other servers. However, the WebSocket connection remains tied to the server the client initially connected to.

Using a traditional backplane, routing HTTP requests to a server without the active WebSocket connection causes "No connection with that ID" errors.

Azure SignalR Service works differently. Instead of clients connecting directly to your servers, they connect to the Azure SignalR Service. This centralizes connection management, allowing requests to be handled by any server without sticky sessions.

Sticky Sessions vs Stateless

When load balancing the backoffice, you need to decide between two approaches:

Option 1: Sticky Sessions with Any Backplane

Configure your load balancer to use sticky sessions (session affinity). This ensures that once a client connects to a server, all subsequent requests from that client go to the same server.

With sticky sessions enabled, any SignalR backplane works:

  • SQL Server backplane

  • Redis backplane

  • Other third-party backplanes

This approach works if your load balancer supports sticky sessions.

Option 2: Stateless with Azure SignalR Service

If you want fully stateless servers without sticky sessions, you need:

This approach requires additional setup but allows for true horizontal scaling without server affinity.

circle-info

Umbraco's cache is built on Microsoft's HybridCache, which automatically uses IDistributedCache as a second-level cache when configured. This means that setting up IDistributedCache for session management also enables distributed caching of Umbraco content across all servers. See Cache Settings for more information.

Choosing the Right Backplane

Choosing the right backplane comes down to a few factors:

  • Whether you can use sticky sessions

  • Message throughput requirements

  • Cost

  • The infrastructure you already have in place

Microsoft has a good list of available backplanes in its SignalR load balancing articlearrow-up-right, including a list of well-known third-party offeringsarrow-up-right.

Code examples

The following code examples show how you can activate SignalR load balancing using an Umbraco composer.

circle-info

Both Umbraco and these composers use .AddSignalR(). This duplication isn't a concern as the underlying code registers the required services as singletons.

Using existing infrastructure

It is possible to use your existing database as a backplane. If this database is hosted in Azure it is not possible to enable Service Broker which will have an impact on message throughput. Nevertheless, it might be sufficient to cover your needs. For more information, check out the GitHub pagearrow-up-right.

  • Add a reference to the IntelliTect.AspNetCore.SignalR.SqlServer NuGet package.

  • Add the following composer to your project:

Azure SignalR Service

  • Set up a resource as described in the Microsoft tutorialarrow-up-right.

  • Make sure the connectionstring is set up under the following key: Azure:SignalR:ConnectionString.

  • Add a reference to Microsoft.Azure.SignalR NuGet package.

  • Add the following composer to your project:

Last updated

Was this helpful?