【问题标题】:Implementing SOA with RESTful service and application APIs?使用 RESTful 服务和应用程序 API 实现 SOA?
【发布时间】:2018-06-27 20:55:44
【问题描述】:

目前,我们有一个庞大的 API,供我们的后台、前端和公共 API 使用。

这让我很头疼,因为在构建新端点时,我在代码中发现了很多应用程序特定的逻辑,这些逻辑我不一定要包含在我的端点中。例如,创建用户的代码可能包含发送欢迎电子邮件的代码,但因为后台端点不需要这样做,所以我需要添加一个没有该逻辑的新端点。

我正在考虑进行一次大型重构,将我们的代码库分解为多个较小且高度特定的服务 API,然后在这些 API 之上构建一组小型应用 API。

因此,例如,用于创建新用户的应用程序端点在重构后可能会执行以下操作:

customerService.createCustomer();
paymentService.chargeCard();
emailService.sendWelcomeEmail();

应用程序和服务 API 将是完全独立的代码库(也许每个服务都有一个单独的代码库),它们也可以使用不同的语言构建。它们只会通过 REST API 调用进行交互。它们将位于同一个本地网络上,因此延迟应该不是一个大问题。

这是个坏主意吗?我以前从未见过/工作过将两者分开的代码库,所以也许有更好的架构来实现我正在寻找的灵活性和可维护性?

建议、链接或 cmets 将不胜感激。

【问题讨论】:

  • 创建几个专用且可重用的服务确实是个好主意。当我看到您的工作流程时,我认为您应该尝试使用事件驱动架构。因此,当创建用户时,您的应用程序只需发送一个包含新用户联系信息的事件。另一个专用应用程序只等待此类事件并将邮件发送给新客户。如果您有多个此类交互,那么引入事件总线可能是值得的。如果不是您的方法,则已经有效。

标签: rest api architecture soa


【解决方案1】:

您制作多个、定义明确的服务的想法是合理的,并且确实是实现这一目标的最佳方式。采用纯粹的微服务方法,无论它看起来多么流行,都被证明是一种矫枉过正的做法。这就是为什么我会正确地重新设计现有的 API/服务,并遵循以下可靠的 SOA 设计原则。在serviceorientation.comsoapatterns.org 都可以找到好的资源,我一直将它们作为我职业生涯的参考。

考虑您需要哪些类型的服务

(图片来自serviceorientation.com)

  • 实体服务通常是您的客户、支付服务 - 例如。以您域中的实体为中心的服务。它们应该与业务无关,并且能够在所有场景中重用。如果足以满足他们的需求,他们有时可以由客户直接调用。它们可以被任务服务调用。
  • 实用程序服务包含您可能在其他服务中重用的逻辑,但通常不会由客户端直接调用。相反,它们会被任务和实体服务调用。一个示例可能是音译服务。
  • 任务服务将实体和实用程序服务组合并重用为有意义的任务。大多数情况下,它们并不是那么不可知论,它们确实实现了一些特定的业务逻辑。他们拥有有意义的业务运营,是客户最常称呼的。

重新设计时要遵循的原则

我强烈建议您前往over this cheat sheet,并确保在重新设计时涵盖所有内容。这是很大的帮助。

一般来说,您应该确保:

  1. 每个服务都有一个公共上下文,并遵循关注点分离原则。例如。 Clients服务只针对客户端相关操作等。

  2. 每个实体和实用程序服务都与业务无关且足够基本。因此它可以在多个场景和上下文中重复使用而无需更改。合约必须简单 - CRUD 并且只有在大多数使用场景中有意义的常见操作。

  3. 服务遵循通用数据模型 - 确保您使用的所有数据结构在所有服务中统一使用,以防止未来需要进行集成并促进服务组合供客户利用。如果您需要接收其他服务返回的客户,则无需转换即可实现此操作

好的,但是非不可知逻辑应该放在哪里?

现在,只要您需要复杂的业务功能,您就有多种选择来抽象业务逻辑。这取决于您要选择的方案:

  • 将逻辑留给所有客户端。让他们结合您的简化服务
  • 如果有业务逻辑通常在您的多个应用程序中实现并且有可能被大量重用,您可以实现一个复合服务,重用多个现有的底层服务并公开逻辑。

服务可组合性。对多个 API 调用通信开销的担忧。

嗯,这是一个古老的问题——当它们可能会产生一些通信开销时,您是否应该进行多次 API 调用?答案是——这取决于你的场景有多复杂、你期望的重用程度以及你想要的灵活性。速度也很关键吗?到什么程度?不过,在面向服务的架构中,这是一种非常常见的方法 - 重用现有服务并根据需要将它们组合到新的配置中。是的,它确实增加了一些开销,但我已经看到在非常复杂的环境中实现,例如电信,由于使用 ESB 解决方案、消息队列等,与收益相比,开销可以忽略不计。这是一种常见的架构方法(图片来自 serviceorientation.com):

强制遗留​​重构提示

通常情况下,为多个现有客户端系统更改已建立的合同是一件很麻烦的事情,很可能会导致大量重构,并且需要在某个深度(可能) 遗留代码。业务逻辑可能分散在各处。因此,请确保您已准备好并拥有控制权、时间和意志来领导这场战斗。

希望对你有帮助

【讨论】:

    【解决方案2】:

    这是个坏主意吗?

    不,但要提供非常具体的建议,这是一个很大的整体问题。

    我想将其分为 3 个区域:

    • 接近
    • 设计
    • 技术

    向后工作,技术是最后也是最具体的部分,完全取决于您当前的环境(平台、技能),并且(希望)合理不言而喻一旦其他事情正在进行中,你就可以了。

    您在上面概述的 设计 似乎是一个很好的最终状态 - 拥有多个特定的、专注的 API,每个 API 都有自己的职责。同样,设计的细节将取决于您和您的组织的技能,以及您拥有的现有平台。例如。如果您已经在使用 TIBCO(例如)并进行了大量投资(许可证、平台、工具、人员),那么利用他们发布的一些模式/设计/模板是有意义的;但是(可能)如果您还没有接触过 TIBCO,则不会。

    抽象地说,REST API 服务似乎是一个很好的起点——系统的各个层面都有很多工具和平台,用于安全、部署、监控、可扩展性等。如果你是 NGINX 用户,他们关于如何做到这一点也有很多(与平台无关的)想法NGINX blog,包括一些关于可扩展性和性能的聪明思考。如果您更喜欢冒险,并且拥有一支聪明、热心的团队,请查看事件驱动架构 - 请参阅 this

    方法(或过程) 是这里的关键。归根结底,这是一次重构,尽管您对“大型重构”的描述确实让我有些害怕——这样说来,听起来您正在谈论一个大爆炸式的变化并称其为重构。也许它只是语言,但我的想法是“将‘一个巨大的 API’演变成多个、特定的、专注的 API(通过重构架构)”。一个起点是Martin Fowler,虽然这本书是关于重构软件的,但原理和方法是相同的,只是在更高的层次上。确实,他只是在谈论这个here

    IBM 谈论 refactoring to microservices 并让它听起来很容易一步完成,但它从来都不是(在实验室之外)。

    您有一个现有的 API,为多个内部和外部客户端提供服务。我会建议你要为这些客户保持这个接口的可靠——将你对实现的重构与与外部系统/组联络和协调的额外问题分开。我的高级入门方法是:

    • 在 API 上标识少量 (3-7) 相关方法
      • 理想情况下,如果无论如何都需要使用这些方法进行重大的、有限范围的更改,那很好 - 代码更改带来的商业价值
    • 专门为这些方法设计/指定新的独立 API
      • 首先,克隆现有的模型/命名/样式
    • 为这些代码编写新服务
      • 具有适当的自动化 CI/CD 测试和部署实践
      • 具有相关监控
    • 修改现有 API 以使对这些方法的调用重定向到调用新服务
      • 也许有一个运行时切换来在旧实现和新实现之间切换
    • 从代码库中删除旧的实现
    • 在此过程中捕获问题、假设和问题
      • 第一遍需要大量了解哪些有效,哪些无效。
    • 然后一遍又一遍地重复该过程,每次都进行改进。

    在未来的某个时间点,由于其他业务驱动的需求,发布到后端、前端和/或公共客户端的 API 可能会发生变化,但这是一个完全不同的项目。

    如您所见,如果 API 很大(1,000 个方法 => 140 个版本),这是一个需要数月的过程,并且有一个合理频繁的发布时间表很重要。并且可能没有任何价值可以改进可靠运行且永不更改的代码,因此现有 API 的大部分(可能)可能会保留下来,只是被新的 API 包装。

    其他注意事项:

    我能给出的最大的 4 条建议可能是:

    • 考虑重构:小的不影响功能的更改
    • 思考敏捷:有价值、可测试、可实现的增量
    • 持续思考:对您将(最终)到达的地方有一个远见,然后持续处理该过程
      • 编写脚本并自动化从代码、文档、测试、部署、监控等流程...
      • 每次都改进!
    • 您有一个可以工作的应用程序/API - 让它继续工作!
      • 这始终是第一要务(您只需努力腾出时间/预算进行维护)

    【讨论】:

    • 嘿,非常感谢您提供的所有信息。稍后我将查看您提供的那些链接。不过,作为快速跟进,您对我的双层 API 方法有什么具体想法吗?例如,我们在前端运行 Angular,并从前端进行三个不同的服务 API 调用只是为了注册客户(参见我的示例)对我来说似乎是糟糕的设计,这就是我考虑添加第二层的原因。有没有更典型的方法来解决这个问题?
    • 您最终会得到不同的层级、不同的职责和粒度。在较低级别,您将拥有非常专注和特定职责的服务/API,这意味着它们的 API/接口非常细粒度。更容易避免内聚和维护这些服务/API/接口,但对您的客户来说更复杂。因此,对于更关注客户端/用户/业务的 API,这类似于编排层 - 请参阅 thenextweb.com/dd/2013/12/17/… 以获取快速示例。
    【解决方案3】:

    一点也不坏。

    您还看到微服务拱门。随之而来的问题是如何将系统分解为定义明确的服务。

    我们使用领域驱动设计架构。将我们的系统分解为微服务和lagom 框架,这允许每个服务都处于差异状态。代码库和事件驱动架构。微服务之间。

    现在让我们从底层看一下您的问题:您说服务包含创建用户和发送电子邮件之类的代码,以及仅创建用户的代码,并且可能还有其他代码。

    首先我们需要了解你正在编写多少种代码:

    1. 域对象逻辑(例如:用户对象)——哪些参数是有效的以及所有的——这应该独立于服务端点,并且应该封装在一个类中,如用户类,我们说它是域驱动设计术语中的聚合
    2. 业务反应——比如在创建用户时发送电子邮件——使用事件驱动架构。这些类型的逻辑分为流程管理器或 sagas,大多数情况下可以有条件地工作,例如为外部创建的用户发送邮件和为内部创建的用户发送电子邮件,通过在事件中有额外的数据

    还有你目前的做法,你是如何处理跨服务事务的???

    【讨论】:

    • 我们目前有一个单体 Java 后端。我正在考虑将其分解为更小的代码库并使用 REST 跨服务进行事务。我真的不知道建立微服务的好方法。我确信这可能不是最好的方法,但到目前为止,我还没有真正找到“正确”的方法来做我想做的事情。
    • 使用 REST 跨服务的事务 --- 你的意思是什么,你可能需要一个 saga 或流程管理器。您也可以使用领域驱动设计首先了解您的系统应该如何分解,然后对于 impl 您可以使用 lagom
    猜你喜欢
    • 2017-03-21
    • 1970-01-01
    • 2014-04-23
    • 2011-07-19
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多