5

假设我们有一个如下图所示的 SOA 基础架构,并且每个服务都可以在不同的主机上运行(这对于两个外网服务“网站”和“支付系统”尤其有效)。

SOA 基础架构

显然我们有一个数据(持久性)层。假设它是通过 EJB + JPA 或类似的方式实现的。

如果我们想在不同的服务之间加入数据(在用户 UI 中),我至少看到了两种选择:

  • 我们希望在 RDBMS 级别进行高效的 JOIN,因此我们有一个包(即 persistence.package),其中包含所有实体和会话外观(CRUD 实现),它们必须以某种方式共享(如何?)为每个服务部署. 也就是说,如果我在 order 模式中更改某些内容,我必须重新部署这些包,从而在几乎所有内容之间引入紧密耦合。此外,数据库必须是唯一的和共享的。

  • 为避免此类问题,我们为每个不同的服务(即 order.package)保留一个实体包,并让服务通过某种协议(soap、rest、esb 等)进行通信。所以我们可以在每个主机本地保存数据(不共享架构),我们不需要重新部署实体包。但是这种方法对于数据挖掘来说很糟糕,因为必须在多个服务之间搜索和返回相关数据的查询效率非常低(因为我们不能进行 SQL 连接)

对于上述问题,是否有更好/标准的方法?

4

2 回答 2

5

SOA 的主要动机是可以单独更改的独立组件。正如 Marco 提到的,第二个动机是将系统简化为更容易解决的小问题。不同服务的优点是灵活性,缺点是更多的管理和开销——开销应该由你得到的结果来证明——例如,参见我发布的 SOA 反模式,称为Nanoservices,它讨论了这种平衡

要记住的另一件事是,Web 服务 API 并不自动意味着这是服务边界。属于一个更大服务的几个 API 仍然可以连接到下面的同一个数据库。因此,例如,如果在您的系统中付款和订单属于一起,您不应该仅仅因为它们是不同的 API 而将它们分开(在许多系统中,这些确实是不同的问题,但同样,这不是自动的)

如果您确实发现服务的分离是合乎逻辑的,那么您应该遵循 Marco 的建议并确保服务是隔离的并且不共享数据库。以这种方式隔离服务有助于他们改变的能力。然后,您可以将它们与复合前端集成到 UI 中。您应该注意,这对于应用程序的操作方面非常有效,因为您只需要每个服务中的几个项目。对于报告,您需要汇总报告之类的东西,即将数据的不可变副本导出到为报告优化的中央数据库(例如非规范化星型模式等)

于 2013-04-01T15:45:42.697 回答
3

哦,我的朋友,你只是让整个场景复杂化,但这不是你的错,像 MSFT、甲骨文和其他大型企业级软件供应商这样的公司喜欢对更容易的事情进行全面了解,他们这样做是为了一个原因:垂直扩展服务意味着更多的许可证。

您可以采取不同的方法,暂时忘记所有那些大词,EJB,JPA ......就像有人曾经说过的那样,将大问题分成较小的部分,这样您就不会遇到大问题了理论上应该更容易处理的小问题。

因此,您的系统中有几个服务:人员、支付系统、订单、产品、ERP ......暂时让我们认为这些边界在业务实体方面是正确的。想象一下,这些服务是贵公司的不同物理部门,这意味着他们只关心属于他们的数据,而不关心其他。

然后你可以说支付部门有自己的数据库,同样适用于订单,当然他们仍然需要像所有部门一样相互通信,这可以通过系统生成的公共代理密钥来轻松实现。这一切意味着每个服务使用内部密钥维护其所有内部实体的引用完整性,但如果需要将记录提供给其他服务,您可以例如使用 Guid 密钥,例如:

在此处输入图像描述

支付服务需要订单 ID 和客户 ID,但这些实体属于它们自己的服务,因此不是共享每条记录的私钥(主键),而是每条记录都有一个主键和一个代理外部键服务将用于在它们之间共享。问题是,您应该致力于构建松散耦合的服务,每个服务都有自己的“小型”数据库。每个服务也应该有自己的 API,这些 API 不仅应该被前端使用,也应该被其他服务使用。您应该避免的另一件事是使用 DTC 或其他事务管理提供程序作为服务范围的事务担保人,它可以通过不同的架构方法轻松存档。

无论如何,请阅读,如果您还没有了解 DDD,它将为您提供有关如何构建企业级软件的不同概述,并且顺便说一下 EJB,远离它们。

更新:

您可以使用事件 SOA 之类的东西,但让我们在这里保持简单。注册客户来到您的网站下订单。对此负责的服务是订单。将产品的外部 ID 列表提交给 Orders 服务,然后注册订单,此时订单处于“等待付款”状态,该服务返回公共 Guid 订单 ID。为了完成订单,客户需要支付货款。付款详细信息被提交给尝试处理付款的付款服务,但为此它需要订单详细信息,因为前端发送的唯一内容是订单 ID,为此它使用 GetOrderDetails(Guid orderId) 来自订单的 API。一旦支付完成,支付服务就会调用 Order 的 API PaymentWasCompletedForOrder(Guid orderID) 的另一个方法。让我知道如果有什么你没有得到。

于 2013-04-01T03:40:11.067 回答