3

因此,我查看了人们为 Duplex Communications 创建的示例示例,即由 IIS 托管并通过 Silverlight 连接时。有很多这样的例子(这篇 MSDN 文章很棒),但使用相同的范例:

用户 A 连接到服务器 A,它将他放在内存列表中以接收未来的更新。
用户 B 连接到服务器 A,它通知列表中的所有用户有人“登录”。

...但是当

用户 C 连接到服务器 C,服务器 C 的内存列表不包含用户 A 或 B。

问题是我希望在集群(网络场)环境中实现这一点。这使事情变得复杂,因为我无法验证哪台机器最终会执行 wcf 调用,因此很难将任何消息转发给所有其他用户。

我能想到的最佳方案是让客户端实际连接到某种路由服务,该服务接收传入请求并将客户端转发到特定机器。当然,这样我就失去了网络农场的好处,因为一台机器有效地处理了所有传入的请求。

一个不太有效的解决方案是让服务不断轮询某些东西(文件服务器上的文件或数据库中的表)以查找更改。一旦出现更改,将它们推送给客户端。这看起来像一个非常丑陋的婴儿。

我错过了什么?

更新 - 路由系统无法满足我的需要。我的托管公司不允许我通过 IP 直接连接到场中的特定机器。我只能连接到通用负载平衡器前端,所以不能保证我的用户会在同一台服务器上结束。

到目前为止,我们正在轮询数据库中的表以查找更改。看起来仍然像一个丑陋的婴儿。

4

8 回答 8

2

假设除了可以在每台服务器上安装的内容(即没有 MSMQ、没有 ESB 等)之外,您对环境的控制为零,那么我会考虑使用 WCF 在服务器之间进行通信。简单的问题似乎是您有一个内存列表需要在两台服务器之间保持同步,并且每当列表的内容发生变化时,都需要通知两台服务器的用户。

通过服务器托管和使用的内部 WCF 服务,您可以使用简单的即发即弃消息来保持列表同步。想象以下场景:

  1. “用户 A”登录到服务器 A
    1. 将“用户 A”添加到在线用户列表
    2. 向服务器 B 发送消息以通知它添加了“用户 A”
      1. 导致服务器 B 将“用户 A”添加到其在线用户列表中
      2. 使服务器 B 通知所有用户用户登录
    3. 通知服务器 A 上的所有用户用户登录
  2. “用户 B”登录到服务器 B
    1. 将“用户 B”添加到在线用户列表
    2. 向服务器 A 发送消息以通知它添加了“用户 B”
      1. 导致服务器 A 将“用户 B”添加到其在线用户列表中
      2. 使服务器 A 通知所有用户用户登录
    3. 通知服务器 B 上的所有用户用户登录
  3. “用户 A”从服务器 A 注销
    1. 从在线用户列表中删除“用户 A”
    2. 向服务器 B 发送消息以通知它已删除“用户 A”
      1. 导致服务器 B 从其在线用户列表中删除“用户 A”
      2. 使服务器 B 通知所有用户用户注销
    3. 通知服务器 A 上的所有用户用户注销
  4. 定期地,让服务器 A 和服务器 B 相互同步它们的列表(可以实现 Ping-Pong 样式...一个服务器将其列表 ping 到另一个服务器,其他服务器合并和 pong 合并列表返回)

上述场景显然假设您能够在托管服务器上安装 WCF 服务,以便它们可以相互通信。我不确定您是否有能力在每台服务器内部了解其他服务器,因为您提到所有流量都必须通过负载平衡器。

于 2009-08-27T23:34:25.390 回答
1

您的解决方案提供商是否使用 MS SQL 作为数据库服务器?如果您拥有 MS SQL 数据库的完全权限,则可以实现 T-SQL 触发器。您可以编写一个触发器,在发生数据库 CRUD 操作时执行代码。使用当前版本的 MS SQL,您甚至可以执行托管 (C#/VB#) 代码。

该解决方案将非常复杂但可能。我会为您的集群使用中央 MS SQL 并编写一些 T-SQL 触发代码。当您关心的记录被修改/等时,我会让 SQL 服务器向集群中的其他服务器发送特殊的 HTTP Web 请求消息(假设集群中的服务器可以任意与其他/所有集群服务器通信)让他们知道任何变化。然后每个服务器可以使用全局应用程序缓存来广播服务器上每个会话的更改。

这是我的顶峰建议。

-杰夫

于 2009-08-27T08:21:37.880 回答
1

看起来您需要使用对等网络(netPeerTcpBinding)。我不确定您的托管环境是否支持这一点。

http://msdn.microsoft.com/en-us/library/cc297274.aspx

于 2009-08-28T16:02:37.837 回答
1

使用 Memcached 或 MSMQ。

使用 Memcached,您可以将它用作所有需要广播的项目的单一事实点。因此,当您获得客户端登录时,您会将一些简单的数据转储到 Memcached 中。它通知其他服务器并更新其他服务器的列表。然后,当您发布信息时,查询 Memcached。

使用 MSMQ,将登录信息推送到队列,然后在两台服务器上实现侦听器,从队列中读取并更新其内存中的“可发布”信息列表。这样,两台服务器都可以随时了解需要发布的数据。

于 2009-08-25T15:05:13.267 回答
1

假设您不需要实时类型的通知,典型的方法是使用后端会话数据库或专用会话服务器,以便所有当前登录的用户对所有集群计算机都是可见的。然后你可以编写一个轮询服务来发送更改通知,或者根据你的要求更高级的东西。

在您的示例中,您会将“内存中”用户列表移动到共享内存服务器或共享数据库。您当然可以实现某种集群更新通知以发送到所有机器,但其复杂性可能超出您的需要。

于 2009-08-10T23:01:56.187 回答
1

服务器之间可以直接通信吗?如果是这样,您可能希望设置只有场中的其他服务器才能连接到的专用终结点。然后,当服务器 C 收到一条消息时,它会向服务器 A 发送一条消息,通知它这一事实,然后服务器 A 可以将其转发给它的客户端。

于 2009-08-22T05:41:25.970 回答
0

您可以使用“Sticky IP”配置您的网络场。

这意味着当客户端连接到网络场时,他会被路由到一台机器。来自该客户端的所有后续请求都将发送到场中的同一台计算机。这有点像您在问题中描述的路由服务。

编辑

实现一个轮询系统可能是最简单的,其中 silverlight 客户端询问 Web 服务器“我有什么新东西吗”,该请求将包含客户端最后一次询问的时间。新事物列表将存储在数据库表中。所以你点击哪个网络服务器没问题。

此外,您需要注意 Silverlight WCF 中的限制,如果我理解正确的话,它并没有实现所有 WCF。

编辑 2

在您需要同时与所有用户通信的情况下,调用不需要一直到数据库。这可以在 WCF 服务级别缓存在内存中,其他客户端将从内存中获取它,从而为您提供更好的性能和更少的数据库负载。

编辑 3

只要您使用的是 silverlight 客户端,客户端就很难直接相互通信。尽管需要额外的工作/成本,但有两种可能性:

  • 使用 Azure 服务总线,每个客户端都与云中的一个端点对话,该端点被转换为直接通信。
  • 使用 silverlight 删除,使用可以公开 WCF 服务端点的客户端。当客户端启动时,它会向服务器注册端点。然后,每个客户端都可以询问在线的服务器并直接向客户端发送消息。
于 2009-07-30T13:22:58.827 回答
0

MS 的速度项目可能是比数据库后端更快的解决方案;它是一个内存缓存层,包含所有集群/故障转移花哨的东西……你可以在 WEB 和 DB 层之间滑动它;它的 API 非常简单,并且也与 .NET 的其余部分保持一致。

于 2009-08-27T23:36:06.040 回答