我希望那里有人遇到这个,或者至少可以发现我的代码有什么问题。
我使用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并且有很多经验,所以我选择了this article。
我包含了nuget包并将我的Startup
类修改为以下
string connectionString = "Server=.;Trusted_Connection=True;Database=CleoChatHost;";
GlobalHost.DependencyResolver.UseSqlServer(connectionString);
app.MapSignalR();
我在IIS中的不同端口上配置了两个网站,以模拟负载平衡环境以进行测试,例如。我将称之为SiteA和SiteB的http://localhost:21215/和http://localhost:21216/
运行每个站点时会发生以下情况:
注意:执行与上述相反的操作会得到相同的结果。
我不知道问题是什么,我检查了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
)
所以要更新上面的问题,我将如何在服务器之间维护{{1}}?我会使用SQL背板来实现这一目标吗?