4

我以前使用过 WCF 服务,现在我有一个新项目即将推出。我仍处于设计阶段,我想知道处理以下场景的最佳方法是什么。

我将有多个客户端同时连接到我的 WCF 服务,在服务上触发不同的方法(操作合同):

A.某些触发的方法只是纯粹的“读取”方法(例如 GetListOfCustomers)。

B.一些触发的方法是复杂的“读取”方法(例如 GetAllProductsByCustomerId)。这种方法需要从数据库中获取客户,检查他的东西,然后获取他购买的所有产品。(意思是,此方法中有 2 次对数据库的调用)。

C.有些是“Write”方法(例如“RemoveCustomer”或“SetProductOutOfStock”)。

我的问题是 - 如何同步所有这些调用,以免出现并发问题?

希望整个服务串行处理调用,因为它会损害客户端的性能(某些调用可能需要 3-4 秒才能处理)。那么我的解决方案是什么?

对具有“多个”线程的所有客户端使用“单个”实例,然后使用锁定对象?这不会导致串行吗?

或者我是否需要一个不同的锁定对象用于“读取”和不同的锁定对象用于“写入”?

还是我需要为“写”功能加锁,而为“读”功能需要其他东西?

这是我在 StackOverflow 上的第一个问题。感谢任何可以提供帮助的人!

更新:我将使用“Linq-To-SQL”作为我的 ORM。

4

4 回答 4

2

您不必担心数据一致性问题,也不必担心执行数据库查询时的并发性。如果我正确理解了您的情况,那么您需要确保的是在执行一系列您希望“原子”的数据库查询时始终如一地使用事务。我将尝试用一个例子来解释它:

  1. 从数据库中获取所有客户。
  2. 对于每个客户,执行更新一些相关数据的查询。

在这种情况下,您不希望发生的情况是,在查询 from返回之后和所有查询 from完成之前,另一个查询更改了数据。例如,如果其中一位客户同时被删除,则更新相关数据毫无意义——这甚至可能导致一些错误。12

所以你需要做的就是把BEGIN TRANSACTION之前1COMMIT之后的东西放在一起2。查找您正在使用的 SQL 方言的确切语法。

基本上,这将确保您正在使用的数据不会改变。事实上,它会被你的交易锁定;并且所有其他可能使用相同数据的查询都在等待您的事务完成。数据库智能地执行这种锁定,总是试图锁定尽可能少的数据。

于 2012-04-15T22:39:06.107 回答
0

我的问题是 - 如何同步所有这些调用,以免出现并发问题?

为什么你需要同步任何东西?DBMS 可以很好地处理同步。当然,如果你知道你会有很多写操作会因为锁而降低你的读性能,那么你将不得不在架构级别上对此进行规划,但这与 WCF 没有太大关系。在这种情况下,正如休所写的那样,CQRS可能是一个合适的选择,尽管没有手头的规范很难说。

我不希望整个服务串行处理调用,因为它会损害客户端的性能(某些调用可能需要 3-4 秒才能处理)。那么我的解决方案是什么?

如果可以的话,然后使用 PerCall 实例化和单并发或多并发。在这里查看有关实例化/并发组合的详细信息。

对具有“多个”线程的所有客户端使用“单个”实例,然后使用锁定对象?这不会导致串行吗?

单实例化会给您带来并发问题,请参阅我上面链接的文章。如果您需要 Singleton 服务,它最有用。


更新

回答您的评论:恐怕我仍然不明白您希望在哪里遇到并发问题。如果您担心 WCF 服务,请避免使用 Single instancing:最具可扩展性的选项是 PerCall/Multiple。

如果您问自己是否需要考虑 CQRS,请随时阅读我在另一条评论中链接的 Udi Dahan 的文章。但请记住,CQRS 需要一些时间来理解并增加您可能需要或可能不需要的项目的复杂性。

我建议不要无用地过度复杂化您的架构,对我来说,为您的服务正确配置实例化/并发性就足够了。如果您不确定,请编写一些原型来伪造系统的预期负载。更安全然后抱歉,特别是如果它是一个长期存在的应用程序。

于 2012-04-16T08:24:32.570 回答
0

您正在为 Web 设计,因此您需要拥抱并发,没有出路。在我看来,使用锁和所有东西并不是在网络上工作的好方法。并发访问即将发生,您需要考虑如何处理并发错误而不是防止并发问题。任何基于 Web 构建的并发控制机制的使用都是有限的,并且很难正确构建。

于 2012-04-16T07:26:37.140 回答
0

我建议您阅读有关CQRS的内容,这是一种架构模式,可以在某种程度上解决您面临的挑战。

作为您的情况的示例解决方案,下图是可以满足您要求的 CQRS 架构。

在此处输入图像描述

如果您需要进一步的解释,我很乐意提供。

更新

主要原则是将数据库读取和写入分开到不同的数据库中。

然后您使用复制来确保您的读取数据库是最新的。

您还可以通过将两个数据库合二为一,将两个服务合二为一来实现上述架构。但是,您最初的问题是基于您的数据库使用模式存在冲突这一事实而引起的数据库争用。

所以这就是我提出 CQRS 作为解决方案的原因——数据库的写入端与读取端分离。读取端可以针对选择进行优化(甚至可以针对访问速度进行非规范化)。

这意味着您将不会遇到与通过同一接口进行读取和写入操作时相同的争用问题 - 这是您当前的方法。

此外,您不需要通过服务公开您的读取操作 - 简单的 ADO 就可以了,服务端点只会引入延迟。

当您从读取模型中读取数据以及数据库写入服务更新数据模型时,您仍然可以使用 linq2sql。

于 2012-04-16T07:37:44.993 回答