WCF - 如何在所有客户到达时执行操作?

时间:2012-04-27 21:51:09

标签: wcf operator-precedence

我有一个WCF服务,可以为多个客户端提供服务。 他们将进行“接受建议匹配”或“拒绝建议匹配”等操作。 我希望所有操作都能按顺序运行,但我担心这会对性能产生影响。

从我看到的 - 默认(和最常用的)实例是'Per Call',默认的并发模式是单一的。

所以我需要在并发中使用'Single'模式吗? 它有多么糟糕?

(我估计最多有几十个客户使用该系统。)

有没有办法享受这两个世界?

使用并行计算(服务与数据库通信)并仍然连续执行操作?

在此post中,我读到了“实例模式=每次调用和并发=单个”:

  • 对于每个客户端实例,将分配一个线程。
  • 对于每个方法调用,都将创建一个新的服务实例。
  • 单个线程将用于为从单个客户端实例生成的所有WCF实例提供服务。

似乎这并不能保证我会连续执行操作调用!

例如,如果发生这种情况:

  1. CLIENT ALPHA调用'Operation A'
  2. CLIENT ALPHA调用'Operation B'
  3. CLIENT BETA调用'Operation C'
  4. 从我读到的内容 - 它说'单个线程将用于服务从单个客户端实例'生成的所有WCF实例。这听起来像是意味着CALL 1和CALL 2将以串行方式执行,但CALL 3可能会在它们之间执行,因为它来自不同的客户端线程。

    这是真的吗?有没有办法确保按照他们到达的顺序处理呼叫?

    有人可以告诉我这是不是一种不好的做法,或者是否有真实世界的场景,在WCF中接受并建议使用这种通信方式。

    非常感谢

1 个答案:

答案 0 :(得分:2)

我认为有3种方法可以回答这个问题

  1. 直接回答
  2. 控制客户端和服务器的情况的替代方法
  3. 您无法控制客户的另一种方法
  4. 我想首先给出答案2和3(因为我觉得它们更好)但我会在最后给出一个直接答案......我保证!

    我认为您的问题并不是您需要按照服务接收的顺序处理邮件,而是因为您拥有独立的客户,您无法保证服务同时收到它们订购它们是从客户发送的

    考虑一下客户ALPHA和BETA的例子。即使客户端ALPHA可能在客户端BETA调用操作C之前将请求发送到呼叫操作2,您也无法知道服务将接收它们的顺序。这意味着即使您按照收到的顺序在服务器上处理它们,这可能仍然是错误的"顺序。

    如果您同意,请继续阅读。如果没有,请直接回到本文底部的直接答案; o)

    方法1:使用WS-Transactions

    如果您同时控制服务和客户端,并且客户端能够实现WS- * SOAP协议(例如.Net WCF客户端)。然后,您可以使用WS-Transaction协议来确保单个客户端中要在单个长时间运行的事务中处理的操作肯定是以这种方式完成的。

    有关如何使用WCF进行WS-Transcation的详细信息,请查看

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

    按照客户端ALPHA和BETA的示例,这将启用客户端ALPHA

    • 开始交易
    • 致电操作1
    • 致电操作2
    • 提交交易

    ALPHA在客户端上启动事务的效果是将该事务传递到服务器,以便它可以创建一个DB事务,以保证操作1和操作2一起完成或根本不完成。

    如果客户端BETA在此过程中调用操作3,则会强制它等待事务提交或中止。请注意,这可能会导致操作3超时,在这种情况下,BETA需要处理该错误。

    此行为适用于任何InstanceContextModeConcurrencyMode

    然而,缺点是这种长时间运行的分布式事务通常不利于可伸缩性。今天你有10个客户,但未来会增长吗?客户是否总能实现WS-Transaction?如果是这样,那么这可能是一个很好的方法。

    方法2:使用"乐观"类型方法

    如果您需要支持许多不同的客户端类型(例如电话,浏览器等),那么您可以允许操作以任何顺序发生,并确保服务和客户端逻辑可以处理故障。

    这可能听起来很糟糕,但

    • 您可以在服务器端使用数据库事务(而不是上面提到的WS-Transaction)以确保您的数据库始终保持一致
    • 每个客户端都可以同步自己的调用,这样在您的示例中,ALPHA会等待调用1完成OK,然后再进行调用2

    这里的缺点是你需要仔细考虑你需要什么样的故障逻辑,并确保客户端和服务代码是健壮的并且行为恰当。

    在您的示例中,我提到ALPHA可以同步自己的调用,但是如果在ALPHA调用操作1之后但在调用操作2之前BETA调用操作3,则可能是

    1. 操作2将失败(例如,操作3删除了操作2尝试更新的记录),在这种情况下,您需要处理该故障。
    2. 操作3将覆盖操作3(例如,操作3更新记录,操作2尝试更新相同的记录)。在这种情况下,您需要决定做什么。您可以让操作2成功,在这种情况下,BETA的更新将丢失。或者,您可以让操作2检测到记录已经更改,因为它已被ALPHA读取然后失败,或者可能通知用户并让他们决定是否要覆盖更改。
    3. 有关MS Entity Framework上下文中的讨论,请参阅

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

      有关它的一般性讨论,请参阅

      http://en.wikipedia.org/wiki/Optimistic_concurrency_control

      同样,在WCF术语中,这适用于任何ConcurrencyModeInstanceContextMode

      这种方法是可扩展性很重要的最常用方法。它的缺点是用户体验可能很差(例如,他们可能会在不知情的情况下覆盖他们的更改)。

      直接回答原始问题

      如果你肯定需要确保邮件是连续处理的,我认为你正在寻找InstanceContextMode.Single

      http://msdn.microsoft.com/en-us/library/system.servicemodel.instancecontextmode.aspx

      这意味着在服务应用程序的生命周期中创建了一个服务类实例。如果您还使用ConcurrencyMode = SingleConcurrencyMode = Reentrant这意味着您的服务一次只会处理一条消息(因为您有一个实例并且它是单线程的)并且消息将在命令他们收到。

      如果您使用ConcurrencyMode = multiple,那么您的单个服务实例将在不同的线程上同时处理多条消息,因此无法保证处理顺序。

      这对性能产生的影响有多大将取决于每个服务调用执行的时间。如果你得到每秒10,每个需要0.1秒,那就没问题了。如果你每秒得到20,而每个通常需要0.1秒,你会看到平均时间增加100%。