Why is Azure SignalR Service recommended when deploying a Blazor Server Side app?

Viewed 4728

When I publish a Blazor Server Side app on Azure, Visual Studio prompts a message that says:

Your application is making use of SignalR. For environments that need to scale we strongly recommend adding a dependency on Azure SignalR Service.

However, my app works just fine as it is, without making use of Azure SignalR Service. So I was wondering if it really makes sense to integrate it or it's just a way for Microsoft to squeeze a few extra dollars from our pockets...

Has anyone tried deploying a Blazor Server Side app with and without Azure SignalR Service, in order to test if there is any actual difference in terms of performance? What kind of advantage should I expect from it?

enter image description here

4 Answers

There are a few variables in play here, so nobody can tell you "Above X clients, you need to use a SignalR service." Depending on how your solution is provisioned, one component or another may be the limiting factor.

For example, the App Service service limits show the maximum number of web sockets per Web App instance. For the Basic tier, it's 350. When you need 351, your options are:

  • Scale up your App Service Plan to Standard or higher.
  • Add an additional instance and use a Redis or Service Bus backplane.
  • Use SignalR service.
  • Disable websockets from SignalR and rely on something like long polling, which is limited by server resources.

After you go to the Standard service tier and scale out to multiple Web App instances, you can get pretty far hosting SignalR yourself. We've run over 5K concurrently connected clients this way with four Standard S3 instances. Four is a misleading number because we needed the horsepower for other portions of our app, not just SignalR.

When hosting SignalR yourself, it imposes some constraints and there are various creative ways you can hang yourself. For example, using SignalR netcore, you're required to have an ARR affinity token for a multi-instance environment. That sucks. And I once implemented tight polling reconnect after a connection was closed from the front end. It was fun when our servers went down for over two minutes, came back up, and we had a few thousand web browsers tight polling trying to reconnect. And in the standard tier Web App, it's really hard to get a handle on just what percentage of memory and CPU multiple websocket connections are consuming.

So after saying all of this, the answer is "it depends on a lot of things." Having done this both ways, I'd go ahead and use SignalR service.

I know this an old question, but I wanted to add some valuable information in regards to costs.

The cost of Azure SignalR can increase drastically and quickly. Messages are divided by 2k in size, so a 10k message will be 5 messages from a billing perspective.

With the free tier you get up to 20 concurrent connections with 20k messages per day, the standard tier allows 1k concurrent connections per unit and 1 million messages per day per unit. Each unit is $49 a month. Then it's $1 per million messages that go over.

This may not seem like a lot, but I have seen a service accrue more than $3,000 worth of SignalR service in just 7 days.

A Blazor Server app is built on top of ASP.NET Core SignalR. Each client communicates to the server over one or more SignalR connections called a circuit. A circuit is Blazor's abstraction over SignalR connections that can tolerate temporary network interruptions. When a Blazor client sees that the SignalR connection is disconnected, it attempts to reconnect to the server using a new SignalR connection.

Each browser screen (browser tab or iframe) that is connected to a Blazor Server app uses a SignalR connection. This is yet another important distinction compared to typical server-rendered apps. In a server-rendered app, opening the same app in multiple browser screens typically doesn't translate into additional resource demands on the server. In a Blazor Server app, each browser screen requires a separate circuit and separate instances of component state to be managed by the server.

Whenever you need to scale the SignalR, you'll need to implement a pattern called backplane. Using Azure SignalR Service, it's already there so you won't need to do it by yourself.

https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-3.1

in case you do not really go to production or this is a pet project just update Blazor Hub configuration to long pooling rather than WebSockets so you will stop getting errors in the console.

        app.UseEndpoints(endpoints =>
        {
            //...
            endpoints.MapBlazorHub(options =>
            {
                options.Transports = HttpTransportType.LongPolling;
            });
            //...
        });

So far for free pricing tier F1 of Azure App Service WebSockets are limited (ref. https://docs.microsoft.com/en-us/azure/app-service/faq-app-service-linux#web-sockets). Ofcource WebSockets are much better than the long pooling approach, it's up to you to decide if you pay for a separate Azure service (Azure SignalR).

Related