We need a doc that describes why Scale-Out providers are needed in SignalR, the two main options (Redis and Azure SignalR Service), and how to configure them.
See:
@anurse can you draft the doc?
@Rick-Anderson someday, sure :)
As part of this, we'll want to show how to hook the disconnect event in case a user wants to add custom behavior when the connection disconnects:
```c#
services.AddSignalR()
.AddMessagePackProtocol()
.AddRedis(o =>
{
o.ConnectionFactory = async writer =>
{
var config = new ConfigurationOptions
{
AbortOnConnectFail = false
};
config.EndPoints.Add(IPAddress.Loopback, 0);
config.SetDefaultPorts();
var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
connection.ConnectionFailed += (_, e) =>
{
Console.WriteLine("Connection Redis failed.");
};
if (!connection.IsConnected)
{
Console.WriteLine("Connection did not connect.");
}
return connection;
};
});
```
(source https://github.com/aspnet/SignalR/issues/2468#issuecomment-414431147)
@anurse Scale-out with SQL Server won't be supported in ASP.NET Core. Since this was supported in ASP.NET 4.x, should we add a "Scale-out differences" section to the Version differences doc?
Sure, that sounds good
@anurse we should add a pointer to this doc from here https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/web-farm?view=aspnetcore-2.1
Some technical notes and a couple images stolen from a PowerPoint I dug up to help illustrate.
Microsoft.AspNetCore.SignalR.StackExchangeRedis
(new in 2.2; we have a different package for 2.1 but we want to guide users to the new one) on the server.AddRedis()
after .AddSignalR()
in ConfigureServices
:public void ConfigureServices(IServiceCollection services)
{
// ... other services ...
services.AddSignalR().AddStackExchangeRedis(redisConnectionString);
// ... other services ...
}
Configure Redis options by passing a second argument (a delegate that can modify the RedisOptions):
public void ConfigureServices(IServiceCollection services)
{
// ... other services ...
services.AddSignalR().AddStackExchangeRedis(redisConnectionString, options =>
{
// change Redis options here
});
// ... other services ...
}
Configuration
- Provides access to StackExchange.Redis's ConfigurationOptions
object. Most of these options can also be provided in the connection string. Options configured here override the ones set in the connection string.ConnectionFactory
- Allows you to provide you own custom logic to create a ConnectionMultiplexer
to use as the connection information. Receives a TextWriter
which can be passed in to the ConnectionMultiplexer
so that log messages will be forwarded.ChannelPrefix
so that multiple applications can share one Redis server.In https://github.com/aspnet/SignalR/issues/3193 @anurse said this:
We don't have SignalR-specific guidance around Redis high-availability. I'd suggest looking at some Redis-specific guidance here. SignalR only uses pub/sub so you don't really need any 'durability' guarantees around your data, you just need to make sure all the servers get all the messages.
We don't officially support clustering (as you noted, there is very limited documentation on Redis right now, this is being worked on in aspnet/Docs#7814). I don't know for sure that it doesn't work, but we don't generally test in that scenario.
So ... Redis clustering is not officially supported. All existing Core SignalR documentation seems to only reference a single Redis server on the backplane.
I understand that only Redis pub/sub functionality is being used so what happens when that Redis server needs to be maintained, patched, restarted? Are SignalR messages only going to be sent to clients attached to the server node that sent the message? (instead of all server nodes). Will SignalR properly reconnect to the Redis server when it comes back after the restart?
If high-availability for Redis is not something that's officially supported or tested I'm trying to determine the implications of having that Redis server as a single-point-of-failure resource. This is something that should be documented & explained since I see many others are trying to find the answer to this exact question.
I've been wondering about the same things that @csatnic-av asks in his comment above - how are we meant to deploy Redis in a way that it can be used as a backplane and also ensure high availability?
As @csatnic-av says:
So ... Redis clustering is not officially supported. All existing Core SignalR documentation seems to only reference a single Redis server on the backplane.
I understand that only Redis pub/sub functionality is being used so what happens when that Redis server needs to be maintained, patched, restarted? Are SignalR messages only going to be sent to clients attached to the server node that sent the message? (instead of all server nodes). Will SignalR properly reconnect to the Redis server when it comes back after the restart?
If high-availability for Redis is not something that's officially supported or tested I'm trying to determine the implications of having that Redis server as a single-point-of-failure resource. This is something that should be documented & explained since I see many others are trying to find the answer to this exact question.
I've read the new documentation here and here but it doesn't seem to address this question, even though it was written in response to this issue.
Since I'm working in Kubernetes I've also tried the Sentinel master-slave topology using the Binnami Redis Helm Chart, but this does not seem usable for the backplane as it deploys separate Kubernetes services for master (writing) and slave (reading), whereas the C# extension method AddStackExchangeRedis(), which sets up the backplane, only allows a single Redis connection string for both reading and writing. So it does not seem possible to use this topology either.
Most helpful comment
In https://github.com/aspnet/SignalR/issues/3193 @anurse said this:
So ... Redis clustering is not officially supported. All existing Core SignalR documentation seems to only reference a single Redis server on the backplane.
I understand that only Redis pub/sub functionality is being used so what happens when that Redis server needs to be maintained, patched, restarted? Are SignalR messages only going to be sent to clients attached to the server node that sent the message? (instead of all server nodes). Will SignalR properly reconnect to the Redis server when it comes back after the restart?
If high-availability for Redis is not something that's officially supported or tested I'm trying to determine the implications of having that Redis server as a single-point-of-failure resource. This is something that should be documented & explained since I see many others are trying to find the answer to this exact question.