通过将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可以更容易地实现冗余。
以上。
这就是上述的全部内容。
总之,就是这样。
综上所述。
简言之。