群集环境中的WCF双工通信

时间:2009-07-30 13:13:32

标签: c# wcf silverlight web-services duplex

因此,我查看人们为Duplex Communications创建的示例示例,即由IIS托管并通过Silverlight连接。有很多这方面的例子(this MSDN article is great),但所有使用相同的范例:

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

......但是当

时会发生什么

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

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

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

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

我错过了什么?

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

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

8 个答案:

答案 0 :(得分: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到其他服务器, 其他服务器合并和pongs合并列表返回)
  5. 上述情况显然假设您能够在托管服务器上安装WCF服务,以便它们可以相互通信。我不确定你是否有能力在每个服务器内部知道其他服务器,因为你提到所有流量必须通过负载均衡器。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

使用Memcached或MSMQ。

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

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

答案 4 :(得分:1)

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

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

这是我的偏见建议。

-Jeff

答案 5 :(得分:1)

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

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

答案 6 :(得分:0)

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

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

修改

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

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

编辑2

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

编辑3

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

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

答案 7 :(得分:0)

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