群集环境中的WCF双工通信

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

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

……但是什么时候会发生什么

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

问题是我希望在集群(Web场)环境中实现它。 这使事情变得复杂,因为我无法validation哪个机器最终会调用wcf调用,因此将任何消息转发给所有其他用户是很困难的。

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

一种不太有效的解决方案是让服务不断轮询某些内容(文件服务器上的文件或数据库中的表)查找更改。 一旦出现更改,请将其推送给客户端。 这似乎是一个非常丑陋的婴儿,所以。

我错过了什么?

更新 – 路由系统不可能满足我的需求。 我的托管公司不允许我通过IP直接连接到服务器场中的特定计算机。 我只能连接到通用负载均衡器前端,因此无法保证我的用户最终会在同一台服务器上运行。

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

假设您对环境的控制超出了每个服务器上可以安装的范围(即没有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到其他服务器,其他服务器合并和pongs合并列表返回)

上述方案显然假设您能够在托管服务器上安装WCF服务,以便它们可以相互通信。 我不确定你是否有能力在每个服务器内部知道其他服务器,因为你提到所有流量必须通过负载均衡器。

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

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

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

使用Memcached或MSMQ。

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

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

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

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

您可以使用“Sticky IP”配置Web场。

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

编辑

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

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

编辑2

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

编辑3

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

  • 使用Azure服务总线,每个客户端与云中的端点进行通信,并转换为直接通信。
  • 使用Silverlight删除,使用可以公开WCF服务端点的客户端。 当客户端启动时,它会将端点注册到服务器。 然后,每个客户端可以询问在线服务器并直接向客户端发送消息。

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