ASP.NET Core SignalR ,十三:为ASP.NET Core SignalR 扩展建立一个Redis 底板

此为系列文章,对MSDN ASP.NET Core SignalR 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。   

这篇文章解释了设置一个Redis 服务的SignalR 特定的方面,用来扩展一个ASP.NET Core SignalR app。

建立一个Redis底板

  • 部署一个Redis 服务。

对于生产环境,只有当Redis底板运行在与SignalR app 一样的数据中心的时候,我们才推荐使用Redis底板。否则,网络的潜在因素会降低性能。如果你的SignalR app运行在Azure 云上,我们会推荐Azure SignalR 服务而不是Redis底板。你可以为开发和测试环境使用Azure Redis 缓存服务。

更多信息,请看如下资源:ASP.NET Core SignalR production hosting and scalingRedis documentationAzure Redis Cache documentation

  • 在SignalR app中,安装如下NuGet包:Microsoft.AspNetCore.SignalR.StackExchangeRedis。
  • 在Startup.ConfigureServices方法中,调用 AddStackExchangeRedis
services.AddSignalR().AddStackExchangeRedis("<your_Redis_connection_string>");
  • 根据需要配置选项。

大部分选项可以在连接字符串及ConfigurationOptions 对象中被设置。在ConfigurationOptions 中指定的选项会重写在连接字符串中设置的选项。

如下的示例展示了如何在ConfigurationOptions 对象中设置选项。这个示例添加了一个通道前缀,因此多个app可以共享一个Redis实例,如同在以下步骤中解释的那样。

services.AddSignalR()
  .AddStackExchangeRedis(connectionString, options => {
      options.Configuration.ChannelPrefix = "MyApp";
  });

在上述的代码中,options.Configuration被用连接字符串中指定的任何东西来初始化。

关于Redis 选项的更多信息,请参考StackExchange Redis documentation

  • 如果你在为多个SignalR app使用一个Redis 服务,请为各个SignalR app 使用不同的通道前缀。

设置一个通道前缀将一个app 与 使用不同的通道前缀的其他app分割开。如果你不分配不同的前缀,一个app给其自己所有的客户端发送的消息将会发送给使用Redis服务作为底板的所有app的所有客户端。

  • 将你的服务厂负载均衡软件配置为粘滞会话。这里有一些如何做这件事的文档示例:
    • IIS
    • HAProxy
    • Nginx
    • pfSense

Redis 服务错误

当一个Redis 服务挂了的时候,SignalR 会抛出异常,指出消息不会被传输。如下是一些典型的异常消息:

  • Failed writing message
  • Failed to invoke hub method 'MethodName'
  • Connection to Redis failed

SignalR不会缓存消息以在服务恢复的时候再次发送它们。当Redis 服务挂掉的时候发送的任何消息都会丢失。

而当Redis 服务再次可用的时候SignalR将会自动重连。

连接失败的自定义行为

这儿有一个示例,其演示了如何处理Redis连接失败事件:

services.AddSignalR()
        .AddMessagePackProtocol()
        .AddStackExchangeRedis(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 to Redis failed.");
                };

                if (!connection.IsConnected)
                {
                    Console.WriteLine("Did not connect to Redis.");
                }

                return connection;
            };
        });

Redis集群

Redis Clustering 是一个通过使用多个Redis 服务而达到高可用性的方法。集群不被官方支持,但它是可以工作的。

下一步

更多信息,请参考如下资源: