使用 Redis 后端扩展
使用 Redis 后端在多个服务器之间扩展 SignalR,在各实例之间同步消息。
使用 Redis 后端扩展 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
多服务器问题
当 SignalR 在单台服务器上运行时,客户端和服务器会共享连接和组的内存。扩展到两台或更多服务器后,每台服务器只知道自己的连接——在服务器 A 上发送的消息永远到不了连接到服务器 B 的客户端。
什么是回程总线?
回程总线是 SignalR 服务器实例之间共享的消息总线。当一台服务器要发送消息时,它会将消息发布到回程总线;所有服务器都会接收消息,并将其转发给各自的本地连接。
添加 Redis 回程总线
安装 Microsoft.AspNetCore.SignalR.StackExchangeRedis 包,并在 AddSignalR() 之后调用 AddStackExchangeRedis()。
// 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")!);Redis 发布/订阅如何为 SignalR 工作
每个 SignalR 服务器都会订阅 Redis 通道。当服务器 A 为组或用户发布消息时,Redis 会将其传递给所有订阅者(服务器 B、C……),然后这些服务器将消息转发到各自的本地连接。
// 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 them配置选项
针对生产环境微调 Redis 连接:TLS、密码、连接容错能力以及发布/订阅通道前缀。
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 服务
如需完全托管的扩展,请使用 Azure SignalR 服务。它充当回程总线和连接管理器——您的应用服务器变为无状态,并且自身不持有 WebSocket 连接。
// 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 needed粘性会话(非 WebSocket 传输的后备方案)
使用服务器发送事件或长轮询(而非 WebSockets)时,同一客户端必须始终访问同一台服务器——这称为粘性会话。请在负载均衡器或反向代理中配置此项。
# 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 server跨多台服务器的组
回程总线会维护组成员关系。在服务器 A 上将连接添加到组后,服务器 B 会通过 Redis 得知这一变化——对应用程序代码完全透明。
// 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 distribution监控 Redis 发布/订阅
监控 Redis 通道,以验证 SignalR 流量并诊断问题。使用 redis-cli SUBSCRIBE 或 Redis Insights 观察消息流。
# 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"处理 Redis 故障
如果 Redis 不可用,SignalR 会退回到仅本地模式——消息不会跨服务器传递。请为 Redis 连接配置重试策略和告警。
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);
});真实场景:可扩展的聊天架构
在生产环境中,请在负载均衡器后运行 3 个或更多 SignalR 服务器实例,并使用 Redis(或 Azure SignalR 服务)作为回程总线。所有状态都存储在 Redis 中;服务器是无状态且可随时替换的。
// 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=3快速检查
SignalR 回程总线解决了什么问题?
回顾:使用 Redis 回程总线进行扩展
要点:
- 没有回程总线时,一台服务器发送的消息无法到达其他服务器上的客户端
- AddStackExchangeRedis() 会透明地添加 Redis 发布/订阅回程总线
- Azure SignalR 服务提供完全托管的无服务器回程总线替代方案
- 非 WebSocket 传输(SSE、长轮询)需要粘性会话
- 通过回程总线在各服务器之间同步组成员关系
- 配置 AbortOnConnectFail=false 和重试策略,以增强 Redis 的容错能力
常见问题解答
「使用 Redis 后端扩展」课时是免费的吗?
是的 — 「使用 Redis 后端扩展」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「使用 Redis 后端扩展」这节课中我会学到什么?
使用 Redis 后端在多个服务器之间扩展 SignalR,在各实例之间同步消息。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「使用 Redis 后端扩展」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- SignalR 中心与连接
- 组、用户与连接管理
- 强类型中心
- 使用 Redis 后端扩展