Scaling with Redis Backplane
Scale SignalR across multiple servers using a Redis backplane to synchronize messages between instances.
Scaling with Redis Backplane is a free C# Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Multi-Server Problem
When SignalR runs on a single server, clients and the server share memory for connections and groups. Scale to two or more servers and each server only knows about its own connections — a message sent on Server A never reaches clients connected to Server B.
What Is a Backplane?
A backplane is a shared message bus between SignalR server instances. When one server wants to send a message, it publishes to the backplane; all servers receive it and forward it to their local connections.
Adding the Redis Backplane
Install the Microsoft.AspNetCore.SignalR.StackExchangeRedis package and call AddStackExchangeRedis() after AddSignalR().
// dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis
builder.Services.AddSignalR()
.AddStackExchangeRedis("localhost:6379", options =>
{
options.Configuration.ChannelPrefix =
RedisChannel.Literal("myapp"); // namespace your channels
});
// Or from config:
// .AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!);How Redis Pub/Sub Works for SignalR
Each SignalR server subscribes to Redis channels. When server A publishes a message for a group or user, Redis delivers it to all subscribers (servers B, C…), which then forward it to their local connections.
// Server A: client sends message
// Hub on Server A calls:
await Clients.Group("room-42").ReceiveMessage(user, msg);
// Internally SignalR publishes to Redis:
// PUBLISH signalr/myapp/group/room-42 <serialized message>
// Redis delivers to Server B and C
// Both servers find connections in "room-42" and push to themConfiguration Options
Fine-tune the Redis connection for production: TLS, password, connection resilience, and pub/sub channel prefix.
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(
builder.Configuration["Redis:ConnectionString"]!);
opts.Configuration.Password = builder.Configuration["Redis:Password"];
opts.Configuration.Ssl = true;
opts.Configuration.AbortOnConnectFail = false;
opts.Configuration.ConnectRetry = 3;
});Azure SignalR Service
For fully managed scaling, use Azure SignalR Service. It acts as the backplane and connection manager — your app servers become stateless and don't hold WebSocket connections themselves.
// dotnet add package Microsoft.Azure.SignalR
builder.Services.AddSignalR()
.AddAzureSignalR(builder.Configuration["Azure:SignalR:ConnectionString"]!);
// That's it — Azure manages all connections and backplane
// Your server scales to zero when not neededSticky Sessions (Fallback for Non-WebSocket Transport)
When using Server-Sent Events or Long Polling (not WebSockets), the same client must always hit the same server — called sticky sessions. Configure this in your load balancer or reverse proxy.
# Nginx: sticky session config (IP hash)
upstream signalr_servers {
ip_hash; # ensures same client hits same server
server server1:5000;
server server2:5000;
server server3:5000;
}
# Or use cookie-based sticky sessions:
# sticky cookie srv_id expires=1h;
# WebSockets don't need sticky sessions —
# the connection is long-lived on one serverGroups Across Multiple Servers
Group membership is maintained by the backplane. Adding a connection to a group on Server A means Server B knows about it via Redis — transparent to application code.
// This works correctly across servers:
public async Task JoinRoom(string room)
{
// Adds to Redis-backed group
await Groups.AddToGroupAsync(Context.ConnectionId, room);
// Clients.Group sends via Redis to all servers
await Clients.Group(room).UserJoined(Context.User!.Identity!.Name!);
}
// No code changes needed — the Redis backplane handles distributionMonitoring Redis Pub/Sub
Monitor Redis channels to verify SignalR traffic and diagnose issues. Use redis-cli SUBSCRIBE or Redis Insights to observe the message flow.
# redis-cli: monitor all SignalR channels
redis-cli PSUBSCRIBE "myapp*"
# Check active channel subscribers
redis-cli PUBSUB CHANNELS "myapp*"
# Check number of subscribers per channel
redis-cli PUBSUB NUMSUB "myapp/all"Handling Redis Failures
If Redis becomes unavailable, SignalR falls back to local-only mode — messages won't cross servers. Configure retry policies and alerting for Redis connectivity.
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(redisConn);
opts.Configuration.AbortOnConnectFail = false; // don't crash app
opts.Configuration.ConnectRetry = 5;
opts.Configuration.ReconnectRetryPolicy =
new ExponentialRetry(5000, maxDeltaBackoffMilliseconds: 60000);
});Real-World: Scaled Chat Architecture
In production, run 3+ SignalR server instances behind a load balancer, with Redis (or Azure SignalR Service) as the backplane. All state lives in Redis; servers are stateless and disposable.
// Architecture:
// [Browser] -> [Load Balancer (any server, WebSocket)] ->
// [SignalR Server 1] -+
// [SignalR Server 2] -+-> [Redis Pub/Sub] -> all servers
// [SignalR Server 3] -+
// Server code is identical on all instances:
builder.Services.AddSignalR().AddStackExchangeRedis(redisConn);
app.MapHub<ChatHub>("/hubs/chat");
// Scale replicas: kubectl scale deployment chat --replicas=3Quick Check
What problem does a SignalR backplane solve?
Recap: Scaling with Redis Backplane
Key takeaways:
- Without a backplane, messages from one server don't reach clients on other servers
- AddStackExchangeRedis() adds a Redis pub/sub backplane transparently
- Azure SignalR Service provides a fully managed, serverless backplane alternative
- Sticky sessions are required for non-WebSocket transports (SSE, Long Polling)
- Group membership is synchronized across servers via the backplane
- Configure AbortOnConnectFail=false and retry policies for Redis resilience
Frequently asked questions
Is the “Scaling with Redis Backplane” lesson free?
Yes — the full text of “Scaling with Redis Backplane” is free to read here on the web, and the C# Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO.
What will I learn in “Scaling with Redis Backplane”?
Scale SignalR across multiple servers using a Redis backplane to synchronize messages between instances. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C# Academy?
No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Scaling with Redis Backplane” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C# Academy lesson?
Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- SignalR Hubs & Connections
- Groups, Users & Connection Management
- Strongly Typed Hubs
- Scaling with Redis Backplane