通过将ASP.NET Core SignalR与Redis结合使用来实现Hub的冗余备份
首先
调查ASP.NET Core SignalR的冗余机制。
ASP.NET Core SignalR概述
参考:https://learn.microsoft.com/ja-jp/aspnet/core/signalr/introduction
ASP.NET Core SignalR是一个用于构建实时Web功能的开发框架。通过SignalR,可以使用ASP.NET Core构建具有实时双向通信功能的应用程序。SignalR提供了简化了实时Web应用程序开发过程的高级函数库和API,使得开发者可以方便地实现实时数据推送、群组通信和服务端到客户端的通信等功能。详细信息请查阅上述参考链接。
题目

回答:在SignalR的背板中使用Redis。
经过调查,发现可以通过在SignalR的背板中使用Redis来实现对HubServer的冗余。
ASP.NET Core SignalR的托管和扩展参考,请参考以下链接:https://learn.microsoft.com/ja-jp/aspnet/core/signalr/scale
网络配置经过重新评估后


试一试
为了这个目的,我要创建一个测试环境并进行尝试。

测试代码
客户端每秒向中央服务器发送消息”你好。”和自己的进程ID。
中央服务器将收到的消息原封不动地发送回客户端。
这只是一个简单的代码。
客户端使用测试代码
项目模板:控制台应用程序 (.NET 6)
项目名称:SignalRClientApplication
NuGet 添加:Microsoft.AspNetCore.SignalR.Client (6.0.22)
using Microsoft.AspNetCore.SignalR.Client;
namespace SignalRClientApplication
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            while (true)
            {
                try
                {
                    // 接続先URL入力
                    WriteLine("Input HubServer URL : ", ConsoleColor.Yellow);
                    var url = Console.ReadLine();
                    if (string.IsNullOrEmpty(url)) continue;
                    // 接続情報作成
                    WriteLine($"HubServer Connecting...");
                    var connection = new HubConnectionBuilder()
                        .WithUrl(url)
                        .Build();
                    // 接続開始
                    await connection.StartAsync();
                    WriteLine($"HubServer Connected!");
                    // Clientのメソッド登録
                    connection.On<string, string>("ClientMethod", (user, message) =>
                    {
                        WriteLine($"Recv ClientMethod : {message} from {user}{(user == Environment.ProcessId.ToString() ? "(my)" : "(other)")}", ConsoleColor.Blue);
                    });
                    // 接続中
                    while (true)
                    {
                        if (connection.State != HubConnectionState.Connected)
                        {
                            WriteLine($"HubServer DisConnected {url}");
                            break; // 再接続へ
                        }
                        // Hubのメソッド呼び出し
                        await connection.InvokeAsync("HubMethod", Environment.ProcessId.ToString(), "Hello.");
                        await Task.Delay(1000);
                    }
                }
                catch (Exception ex)
                {
                    WriteLine(ex.Message, ConsoleColor.Red);
                }
            };
        }
        // コンソール画面に色分け表示して表示
        private static readonly object lockobj = new();
        private static void WriteLine(string value, ConsoleColor ForegroundColor = ConsoleColor.Gray)
        {
            lock (lockobj)
            {
                Console.ForegroundColor = ForegroundColor;
                Console.WriteLine(value);
                Console.ResetColor();
            }
        }
    }
}
使用HubServer的测试代码
项目模板:ASP.NET Core Web 应用程序 (.NET 6)
项目名称:SignalRHubServerWebApplication
添加NuGet包:Microsoft.AspNetCore.SignalR.StackExchangeRedis (6.0.22)
using StackExchange.Redis;
namespace SignalRHubServerWebApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            // Add services to the container.
            builder.Services.AddRazorPages();
            builder.Services.AddSignalR().AddStackExchangeRedis(configure =>
            {
                configure.Configuration = new ConfigurationOptions
                {
                    ChannelPrefix = "MyApp",
                    EndPoints =
                    {
                        { "192.168.56.106", 6379 } // Redis
                    },
                    AbortOnConnectFail = false,
                };
            });
            var app = builder.Build();
            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthorization();
            app.MapRazorPages();
            app.MapHub<HubServer>("/hub");
            app.Run("http://*:5000");
        }
    }
}
using Microsoft.AspNetCore.SignalR;
namespace SignalRHubServerWebApplication
{
    public class HubServer : Hub
    {
        public async Task HubMethod(string user, string message)
        {
            // Clientのメソッド呼び出し
            await Clients.All.SendAsync("ClientMethod", user, message);
        }
    }
}
Redis构建
简单地写个备忘录。
# テストには邪魔なファイアウォール停止
> sudo systemctl stop firewalld
> sudo systemctl disable firewalld
# Redisインストール
> sudo dnf install redis
全てy
# localhostのみ接続許可になっているので bind から始まる行を見つけて変更する
> sudo vi /etc/redis/redis.conf
# bind 127.0.0.1 -::1
bind * -::*
> sudo systemctl start redis
构建HubServer
准备两台。
# テストには邪魔なファイアウォール停止
> sudo systemctl stop firewalld
> sudo systemctl disable firewalld
# .NET 6ランタイム
> sudo dnf install aspnetcore-runtime-6.0
全てy
# HostServer用テストコードをpublishしてリモートにコピー、実行
> dotnet SignalRHubServerWebApplication.dll
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://[::]:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /root/publish/
客户建立
客戶使用自己的個人電腦。
考试

> dotnet SignalRClientApplication.dll
Input HubServer URL [e.g. http://localhost:5005/hub] :
http://192.168.56.107:5000/hub
HubServer Connecting...
HubServer Connected!
> dotnet SignalRClientApplication.dll
Input HubServer URL [e.g. http://localhost:5005/hub] :
http://192.168.56.108:5000/hub
HubServer Connecting...
HubServer Connected!
连接已建立。
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 23380(other)
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 23380(other)
:
Recv ClientMethod : Hello. from 23380(my)
Recv ClientMethod : Hello. from 1816(other)
Recv ClientMethod : Hello. from 23380(my)
Recv ClientMethod : Hello. from 1816(other)
:
可以看到“Hello.”已经传播到了所有客户端。

客户B检测到HubServer B的停止并断开连接。
HubServer DisConnected http://192.168.56.108:5000/hub
Input HubServer URL :
客户A正常运行,但无法接收来自客户B的消息。
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 1816(my)
:

客户A再次收到客户B的信息。
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 23380(other)
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 23380(other)
:
B客户端也接收到了A客户端的消息。
Input HubServer URL :
http://192.168.56.107:5000/hub
HubServer Connecting...
HubServer Connected!
Recv ClientMethod : Hello. from 23380(my)
Recv ClientMethod : Hello. from 1816(other)
:

客户A也接收来自客户C的消息。
Recv ClientMethod : Hello. from 1816(my)
Recv ClientMethod : Hello. from 23380(other)
Recv ClientMethod : Hello. from 24432(other)
:
客户B也接收来自客户C的消息。
Recv ClientMethod : Hello. from 23380(my)
Recv ClientMethod : Hello. from 24432(other)
Recv ClientMethod : Hello. from 1816(other)
:
客户C收到来自客户A / B的信息。
Input HubServer URL :
http://192.168.56.108:5000/hub
HubServer Connecting...
HubServer Connected!
Recv ClientMethod : Hello. from 24432(my)
Recv ClientMethod : Hello. from 1816(other)
Recv ClientMethod : Hello. from 23380(other)
:
我确认了HubServer的冗余备份正正常运行。
Redis的冗余备份

不过,但本文章不讨论Redis的冗余性。
你可以通过Google搜索找到有价值的信息……。
Redis的冗余化
https://www.sraoss.co.jp/tech-blog/redis/redis-ha/
将Redis配置为冗余化架构(部署故障转移环境-第二部分)
如果使用AWS,使用AWS ElastiCache for Redis或Amazon MemoryDB for Redis,可以更容易地实现冗余。
如果使用Azure,使用Azure SignalR Service可以更容易地实现冗余。
以上。
这就是上述的全部内容。
总之,就是这样。
综上所述。
简言之。
 
    