我希望有人遇到过这个问题,或者至少可以发现我的代码有什么问题。
我使用 MVC 和 SignalR 创建了一个基于浏览器的聊天应用程序,因为我需要一个用户登录聊天我已经针对 MVC 控制器实现了一个注册,它将用户添加到内部 UserList
public static void Register(string userName, string userRole, string userBase, string userLocation)
{
var userInfo = (from user in UsersList where user.Name == userName select user).FirstOrDefault();
if (userInfo != null)
{
userInfo.Location = userLocation;
userInfo.Role = userRole;
userInfo.Base = userBase;
return;
}
var rgx = new Regex("[^a-zA-Z0-9 -]");
UsersList.Add(
new UserInfo
{
Name = userName,
NameId = rgx.Replace(userName, "").Replace(" ", ""),
Base = userBase,
Location = userLocation,
Role = userRole,
Group = "Cleo",
Container = userLocation,
ContainerId = rgx.Replace(userLocation, "").Replace(" ", "").Trim()
});
}
从客户端我实例化chatHub
然后调用Connect
$(function () {
var objHub = $.connection.chatHub;
loadClientMethods(objHub);
$.connection.hub.start().done(function () {
loadEvents(objHub);
});
function loadEvents(objHub) {
$('#hState').val('open');
objHub.server.connect(gloalUserNameId);
}
所有这些在单个服务器上运行良好并且所有连接都保存在内存中,顺便说一句,这已经生产了一年多。
现在,我需要为我们的聊天应用程序建立更好的弹性,例如在负载平衡的环境中,但由于一切都在内存中,我立即遇到了用户 A 连接到服务器 X 和用户 B 连接到服务器 Y 的问题(两者都不能看到另一个,你可以看到问题)。
因此,在网上搜索了很长时间后,我发现了几篇关于使用 Redis 或 SQL 扩展 SignalR 的文章。由于我们公司使用 SQL 并且在这方面有很多经验,所以我选择了这篇文章。
我包含了 nuget 包并将我的Startup
课程修改为以下内容
string connectionString = "Server=.;Trusted_Connection=True;Database=CleoChatHost;";
GlobalHost.DependencyResolver.UseSqlServer(connectionString);
app.MapSignalR();
我在 IIS 中在不同的端口上配置了两个网站,以模拟负载平衡环境以进行测试,例如。http://localhost:21215/和http://localhost:21216/我将称之为 SiteA 和 SiteB
当我运行每个站点时会发生以下情况:
- 使用 ?userName=TestUserA 启动 SiteA,然后使用 ?userName=TestUserB 启动 SiteB -- 结果是 SiteA 加载(最初没有联系人),然后 SiteB 加载,SiteA 用户列表使用 TestUserB 更新。SiteB 没有用户。
注意:执行与上述相反的操作会产生相同的结果。
我不知道问题出在哪里,我检查了 SQL 数据库,可以看到背板已经创建了 SQL 表并且数据正在进入它们。我也尝试使用与上述相同的问题来实现 Redis 解决方案。
有没有人实施过这个并遇到同样的问题?或者任何人都可以解释一下这个问题可能是什么?
编辑
经过进一步的诊断/测试,问题似乎与UserList
每个服务器上维护的内部有关,我相信事件的顺序如下:
UserA
登录SiteA
SiteA
增加UserA
了UserList
_SiteA
SiteA
hub.Connect(...)
从客户端执行,然后Clients.Client(...).DrawTree(...)
执行Clients.AllExcept(...).addUser(...)
- 上述调用更新
SiteA
用户列表,并通知所有连接的客户端有一个新用户 SiteA
已连接且没有活动用户UserB
登录SiteB
SiteB
增加UserB
了UserList
_SiteB
SiteB
hub.Connect(...)
从客户端执行,然后Clients.Client(...).DrawTree(...)
执行Clients.AllExcept(...).addUser(...)
- 前面的调用更新
SiteB
用户列表,并通知所有连接的客户端有一个新用户——这addUser
在SiteA
客户端上执行以添加UserB
到用户列表 SiteB
已连接且没有活动用户,而SiteA
有一个活动用户
我认为问题在于 SQL 背板只会在消息发送时处理它们,并且已经从 SQL 数据库中表的命名约定中确认了这一点。然而,内部UserList
负载平衡服务器之间不同步。SiteA
更新的事实UserB
仅是由于连接addUser
时的广播(意味着仅包含且仅包含)UserB
SiteB
SiteB
UserB
SiteA
UserA
所以要更新我上面的问题,我将如何维护UserList
服务器之间的关系?我会使用 SQL 背板来实现这一点吗?