[译] 微服务的设计模式,java 后端面经
应用所有这些原则会带来一些挑战和问题。让我们讨论这些问题及其解决方案。
分解模式
按业务能力分解
问题
微服务就是要应用单一责任原则使服务松散耦合。但是,将应用程序分成较小的部分必须在逻辑上完成。那么,我们如何将应用程序分解为小型服务呢?
解决
一种策略是按业务能力分解。所谓业务能力就是可以体现企业业务价值的,给定业务的功能集取决于业务类型。例如,保险公司的功能通常包括销售,市场营销,承保,理赔处理,计费,合规性等。每个业务功能都可以视为一种服务,但它是面向业务的,而不是技术的。
按子域分解模式
问题
使用业务功能分解应用程序可能是一个不错的开始,但是您会遇到所谓的“神类”,这些类将不容易分解。它们将在多种服务中通用。例如,订单类将用于“订单管理”,“接单”,“订单交付”等业务中。我们该如何分解它们?
解决
对于“神类”问题,DDD(领域驱动设计)可以解决。它使用子域和有界上下文概念来解决此问题。DDD 将为企业创建的整个域模型分解为子域。每个子域都有一个模型,该模型的范围称为有界上下文。每个微服务将围绕有界的上下文进行开发。
注意:确定子域并非易事。它需要对业务的了解。像业务功能一样,通过分析业务及其组织结构并确定不同的专业领域来标识子域。
扼杀模式
问题
到目前为止,我们讨论的设计模式都是分解未开发的应用程序,但是我们所做的工作中有 80%是用于棕色的应用程序,这是大型的整体应用程序。将上述所有设计模式应用于它们将很困难,因为把他们当作一个整体应用的同时将它们拆分成一个个较小的部分是一项艰巨的任务。
解决
扼杀者模式可以解决此类问题。扼杀者模式是基于藤蔓缠绕植物的类比。此解决方案与 Web 应用程序配合使用,在 Web 应用程序之间来回调用,对于每个 URI 调用,服务可以分为不同的域并作为单独的服务托管。这个想法是一次做一个域。这将创建两个单独的应用程序,它们在同一 URI 空间中并排运行。最终,新重构的应用程序会“扼杀”或替换原始应用程序,直到最终您可以关闭整体应用程序。
整合模式
api 网关模式
问题
当一个应用被分解为多个微服务时,还会有一些问题需要解决。
1.如何调用多个微服务
来抽象生产者信息。
2.在不同的渠道(例如台式机,移动设备和平板电脑)上,由于 UI 可能不同,应用程序需要不同的数据来响应相同的后端服务。
3.不同的使用者对于可重复使用的微服务响应格式可能不同。谁将进行数据转换或现场操作?
4.生产者微服务可能不支持某些类型协议的处理方式。
解决
API 网关有助于解决微服务实现引起的许多问题,而不仅限于上述问题。
1.API 网关是任何微服务调用的单一入口点。
2.它可以用作代理服务,以将请求路由到相关的微服务,从而抽象出生产者详细信息。
3.它可以将对多个服务的请求散发出去,然后汇总结果以发送回消费者。
4.千篇一律的所有 API 不能解决所有消费者的需求;该解决方案可以为每种特定类型的客户端创建一个细粒度的 API。
5.它还可以将协议请求(例如 AMQP)转换为另一个协议(例如 HTTP),反之亦然,以便生产者和消费者可以处理它。
6.它还可以减轻微服务的身份验证/授权责任。
聚合器模式
问题
我们已经讨论了解决 API 网关模式中的聚合数据问题。但是,我们将在这里全面讨论它。
将业务功能分解为几个较小的逻辑代码段时,有必要考虑如何聚合每个服务返回的数据。消费者不能承担此责任,因为这可能需要了解生产者应用程序的内部实现。
解决
聚集器模式有助于解决此问题。它讨论了如何聚合来自不同服务的数据,然后将最终响应发送给消费者。这可以通过两种方式完成:
1.复合微服务将调用所有必需的微服务,合并数据,并在发送回数据之前对其进行转换。
2.API 网关还可以将请求划分为多个微服务并聚合数据,然后再将其发送给使用者。
如果要应用任何业务逻辑,建议选择复合微服务。否则,API 网关是已建立的解决方案。
客户端 UI 组合模式
问题
通过分解业务功能/子域来开发服务时,负责用户体验的服务必须从多个微服务中提取数据。在整体应用中,从 UI 到后端服务只有一次调用,以检索所有数据并刷新/提交 UI 页面。但是,现在不一样了。我们需要了解如何去做。
解决
对于微服务,必须将 UI 设计为具有屏幕/页面的多个部分/区域的框架。每个部分都将调用单个后端微服务以提取数据。这称为组成特定于服务的 UI 组件。诸如 AngularJS 和 ReactJS 之类的框架可以轻松地做到这一点。这些屏幕称为单页应用程序(SPA)。这使应用程序可以刷新屏幕的特定区域而不是刷新整个页面。
数据库模式
每个服务一个数据库
问题
如何定义微服务的数据库体系结构存在一个问题。以下是要解决的问题:
1.服务必须松散耦合。它们可以独立开发,部署和扩展。
2.业务事务可能会强制跨越多个服务的不变量。
3.一些业务事务需要查询多个服务拥有的数据。
4.有时必须复制数据库并对其进行分片以进行扩展。
5.不同的服务具有不同的数据存储要求。
解决
为了解决上述问题,必须为每个微服务设计一个数据库。它必须仅对该服务专用。只能由微服务 API 访问它。其他服务无法直接访问它。例如,对于关系数据库,我们可以使用每个服务一个专用表,每个服务一个 schema 或每个服务一个数据库服务器。每个微服务应具有一个单独的数据库 ID,以便可以给予单独的访问权限以设置障碍并防止其使用其他服务表。
每个服务共享数据库
问题
我们已经讨论了每个服务一个数据库是微服务的理想选择,当应用程序是未开发的并且要使用 DDD 开发时,这是可能的。但是,如果应用程序是一个整体并且试图闯入微服务,那么非规范化就不那么容易了。在那种情况下合适的架构是什么?
解决
每个服务共享数据库不是理想的选择,但这是上述情况的可行解决方案。大多数人认为这是微服务的反模式,但对于棕色应用程序来说,这是将应用程序分解成较小逻辑部分的一个很好的开始。这不适用于未开发的应用程序。在这种模式下,一个数据库可以与一个以上的微服务对齐,但是必须限制为最大 2-3 个微服务,否则伸缩,自治和独立性将难以执行。
命令查询职责隔离(CQRS)
问题
一旦我们实现了每个服务的数据库,就需要进行查询,这需要来自多个服务的联合数据-这是不可能的。那么,我们如何在微服务架构中实现查询?
解决
CQRS 建议将应用程序分为两部分-命令端和查询端。命令行处理创建,更新和删除请求。查询端通过使用实例化视图来处理查询部分。通常将事件源模式与它一起使用来为任何数据更改创建事件。通过订阅事件流,可以使实例化视图保持更新。
saga 模式
问题
当每个服务都有自己的数据库并且一个业务事务跨越多个服务时,我们如何确保各个服务之间的数据一致性?例如,对于客户有信用额度的电子商务应用程序,该应用程序必须确保新订单不会超过客户的信用额度。由于订单和客户位于不同的数据库中,因此应用程序不能简单地使用本地 ACID 事务。
解决
Saga 代表由几个子请求组成的高级业务流程,每个子请求在单个服务中更新数据。每个请求都有一个补偿请求,该请求在请求失败时执行。它可以通过两种方式实现:
1.Choreography-如果没有中央协调,则每个服务都会产生并侦听另一个服务的事件,并决定是否应采取措施。
2.Orchestration-协调员(对象)负责传奇的决策和业务逻辑排序。
可观察性模式
日志汇总
问题
考虑一个用例,其中一个应用程序由在多台计算机上运行的多个服务实例组成。请求通常跨越多个服务实例。每个服务实例均以标准化格式生成日志文件。我们如何通过日志了解特定请求的应用程序行为?
评论