在 SignalR 中处理并发连接
Handling concurrent connections in SiganlR
我正在使用 .Net framework 4.5.2,我将开始制作一个通知系统,从 Web 应用程序向从 windows 表单桌面应用程序连接的用户发送通知。
经过调查,我发现合适的解决方案是使用 signalR,因为它支持在将通知发送到连接的客户端之前过滤通知。
但我担心的是:
当我在 Web 应用程序中创建我的 HUB class 时,我实现了 OnConnected 方法,该方法将检测连接到服务器以接收通知的任何客户端,我考虑过将连接的用户收集到字典中(在内存中)我知道这是一个无法在生产中实施的解决方案,因为在内存变量(字典)中设置连接的用户是不可靠的。在我的例子中,连接的用户数量可能是 20,000
或超过,将来可能会变大。我需要知道跟踪所有连接用户的最佳方式,同时知道处理并发请求而不会出现任何可伸缩性问题的最佳方式。我是新手,请尽快做出决定。
我还需要知道可以在集线器中覆盖的 OnReconnect 方法的用法class。
我还需要知道如果 iis 出于任何原因重新启动 Internet 应用程序,如何处理连接以防止丢失。
Mapping connections to users 可以通过多种方式完成,具体取决于您想要实现的目标:
In memory storage:
最好的方法是使用 concurrent dictionary。这将允许线程安全操作,但正如您所说,这不是大量连接的最佳解决方案。
Permanent external storage
将您的地图保存在数据库中。
好的部分: 映射可跨多个 Web 服务器使用
不好的部分: 数据库压力很大,需要大量清理工作
Single-User Groups
为每个用户创建一个组。这是最简单实用的解决方案。
好的部分:
~ 非常易于使用和实施
~ SignalR 足够聪明,可以在断开连接时从组中删除连接
~ 删除最后一个连接时删除组
~ 如果你使用 Identity,你可以将唯一的组名称存储为声明 [1] [2] 并将其放入你的 hub 中,如:
public static class IdentityExtensions
{
public static string GetSignalRUniqueGroup(this IIdentity identity)
{
var claimsIdentity = identity as ClaimsIdentity;
var claim = claimsIdentity?.FindFirst("uniqueSignalRGroup");
if (claim == null) return null;
try
{
return claim.Value;
}
catch
{
return null;
}
}
}
(不是真的)不好的部分:你必须小心什么用户加入什么组。 !请勿! 在客户端实现加入组功能。相反,使用 OnConnected 和 OnReconnected 将连接添加到组
public override Task OnConnected()
{
string userGroup = Context.User.Identity.GetSignalRUniqueGroup();
if(userGroup != null)
{
Groups.Add(Context.ConnectionId, userGroup);
}
return base.OnConnected();
}
public override Task OnReconnected()
{
string userGroup = Context.User.Identity.GetSignalRUniqueGroup();
if(userGroup != null)
{
Groups.Add(Context.ConnectionId, userGroup);
}
return base.OnReconnected();
}
public override Task OnDisconnected(bool stopCalled)
{
//You should not manually remove the user from the group when the user disconnects.
//This action is automatically performed by the SignalR framework.
return base.OnDisconnected(stopCalled);
}
其他问题,您可以阅读:
Understanding and Handling Connection Lifetime Events in SignalR
我正在使用 .Net framework 4.5.2,我将开始制作一个通知系统,从 Web 应用程序向从 windows 表单桌面应用程序连接的用户发送通知。
经过调查,我发现合适的解决方案是使用 signalR,因为它支持在将通知发送到连接的客户端之前过滤通知。
但我担心的是: 当我在 Web 应用程序中创建我的 HUB class 时,我实现了 OnConnected 方法,该方法将检测连接到服务器以接收通知的任何客户端,我考虑过将连接的用户收集到字典中(在内存中)我知道这是一个无法在生产中实施的解决方案,因为在内存变量(字典)中设置连接的用户是不可靠的。在我的例子中,连接的用户数量可能是 20,000 或超过,将来可能会变大。我需要知道跟踪所有连接用户的最佳方式,同时知道处理并发请求而不会出现任何可伸缩性问题的最佳方式。我是新手,请尽快做出决定。
我还需要知道可以在集线器中覆盖的 OnReconnect 方法的用法class。
我还需要知道如果 iis 出于任何原因重新启动 Internet 应用程序,如何处理连接以防止丢失。
Mapping connections to users 可以通过多种方式完成,具体取决于您想要实现的目标:
In memory storage:
最好的方法是使用 concurrent dictionary。这将允许线程安全操作,但正如您所说,这不是大量连接的最佳解决方案。
Permanent external storage
将您的地图保存在数据库中。
好的部分: 映射可跨多个 Web 服务器使用
不好的部分: 数据库压力很大,需要大量清理工作
Single-User Groups
为每个用户创建一个组。这是最简单实用的解决方案。
好的部分:
~ 非常易于使用和实施
~ SignalR 足够聪明,可以在断开连接时从组中删除连接
~ 删除最后一个连接时删除组
~ 如果你使用 Identity,你可以将唯一的组名称存储为声明 [1] [2] 并将其放入你的 hub 中,如:
public static class IdentityExtensions
{
public static string GetSignalRUniqueGroup(this IIdentity identity)
{
var claimsIdentity = identity as ClaimsIdentity;
var claim = claimsIdentity?.FindFirst("uniqueSignalRGroup");
if (claim == null) return null;
try
{
return claim.Value;
}
catch
{
return null;
}
}
}
(不是真的)不好的部分:你必须小心什么用户加入什么组。 !请勿! 在客户端实现加入组功能。相反,使用 OnConnected 和 OnReconnected 将连接添加到组
public override Task OnConnected()
{
string userGroup = Context.User.Identity.GetSignalRUniqueGroup();
if(userGroup != null)
{
Groups.Add(Context.ConnectionId, userGroup);
}
return base.OnConnected();
}
public override Task OnReconnected()
{
string userGroup = Context.User.Identity.GetSignalRUniqueGroup();
if(userGroup != null)
{
Groups.Add(Context.ConnectionId, userGroup);
}
return base.OnReconnected();
}
public override Task OnDisconnected(bool stopCalled)
{
//You should not manually remove the user from the group when the user disconnects.
//This action is automatically performed by the SignalR framework.
return base.OnDisconnected(stopCalled);
}
其他问题,您可以阅读: Understanding and Handling Connection Lifetime Events in SignalR