问题
如何为微服务定义数据库体系结构是一个问题。以下是需要解决的问题:
-
服务必须松散耦合。它们可以独立地开发、部署和扩展。
-
业务事务可能强制跨多个服务的不变量。
-
一些业务事务需要查询由多个服务拥有的数据。
-
数据库有时必须复制和切分,以便进行扩展。
-
不同的服务有不同的数据存储需求。
解决方案
为了解决上述问题,每个微服务必须设计一个数据库;这项服务必须是私人的。它只能由microservice API访问。其他服务不能直接访问它。例如,对于关系数据库,我们可以使用针对服务的私有表、针对服务的模式或针对服务的数据库-服务器。每个微服务都应该有一个单独的数据库id,以便能够提供单独的访问,以设置障碍,并防止它使用其他服务表。
问题
我们已经讨论过,每个服务有一个数据库对于微服务来说是理想的,但是当应用程序是greenfield并且可以用DDD开发时,这是可能的。但如果应用程序是一个整体,并试图进入微服务,反规范化不是那么容易。在这种情况下,什么是合适的体系结构?
解决方案
每个服务共享数据库并不理想,但这是上述场景的有效解决方案。大多数人认为这是一种针对微服务的反模式,但对于棕地应用程序来说,这是将应用程序分解为更小的逻辑部分的良好开端。这不应该应用于绿地应用。在这种模式中,一个数据库可以与多个微服务对齐,但必须限制在2-3个最大值,否则,伸缩性、自主性和独立性将难以执行。
问题
一旦我们实现了每个服务的数据库,就需要进行查询,这需要来自多个服务的联合数据——这是不可能的。那么,我们如何在微服务体系结构中实现查询呢?
解决方案
CQRS建议将应用程序分为两部分——命令端和查询端。命令端处理创建、更新和删除请求。查询端通过使用物化视图来处理查询部分。事件源模式通常用于为任何数据更改创建事件。物化视图通过订阅事件流来保持更新。
问题
当每个服务都有自己的数据库和跨越多个服务的业务事务时,我们如何确保服务之间的数据一致性?例如,对于客户有信用限额的电子商务应用程序,应用程序必须确保新订单不会超过客户的信用限额。由于订单和客户位于不同的数据库中,应用程序不能简单地使用本地ACID事务。
解决方案
Saga代表由几个子请求组成的高级业务流程,每个子请求在一个服务中更新数据。当请求失败时,每个请求都有一个补偿请求执行。它可以通过两种方式实现:
-
编排——当没有中央协调时,每个服务产生并监听另一个服务的事件,并决定是否应该采取行动。
-
编配——编配者(对象)负责传奇的决策制定和业务逻辑的排序。
问题
考虑一个用例,其中应用程序由在多台机器上运行的多个服务实例组成。请求通常跨越多个服务实例。每个服务实例以标准化格式生成一个日志文件。我们如何通过日志了解特定请求的应用程序行为?
解决方案
我们需要一个集中的日志记录服务来聚合来自每个服务实例的日志。用户可以搜索和分析日志。它们可以配置当日志中出现某些消息时触发的警报。例如,PCF确实有Loggeregator,它从PCF平台的每个组件(路由器、控制器、diego等)以及应用程序中收集日志。AWS云表也做了同样的事情。
问题
当由于微服务体系结构而导致的服务组合增加时,对事务进行监视就变得非常重要,以便在出现问题时可以监视模式并发送警报。我们应该如何收集指标来监控应用程序性能?
解决方案
需要一个度量服务来收集关于单个操作的统计信息。它应该聚合提供报告和警报的应用程序服务的指标。聚合度量有两种模型:
-
推送——服务将指标推送到指标服务,例如NewRelic, AppDynamics
-
Pull - 度量服务从服务中提取度量指标,例如Prometheus
问题
在微服务体系结构中,请求通常跨越多个服务。每个服务通过跨多个服务执行一个或多个操作来处理请求。那么,我们如何跟踪端到端请求来解决问题呢?
解决方案
我们需要一种服务
Spring Cloud Slueth以及Zipkin server都是通用实现。
问题
当实现了微服务体系结构时,服务可能会启动,但无法处理事务。在这种情况下,如何确保请求不会转到那些失败的实例?使用负载平衡模式实现。
解决方案
每个服务都需要有一个端点,可以用来检查应用程序的健康状况,比如/health。这个API应该检查主机的状态、到其他服务/基础设施的连接以及任何特定的逻辑。
Spring Boot Actuator 确实实现了一个/health端点,并且该实现也可以自定义。
问题
服务通常也调用其他服务和数据库。对于开发、QA、UAT、prod等每个环境,端点URL或某些配置属性可能不同。任何这些属性的更改都可能需要重新构建和重新部署服务。如何避免对配置更改进行代码修改?
解决方案
外部化所有配置,包括端点url和凭证。应用程序应该在启动或运行时加载它们。
Spring Cloud config server提供了将属性外部化到GitHub并将其作为环境属性加载的选项。应用程序可以在启动时访问它们,也可以在不重启服务器的情况下刷新它们。
问题
当微服务出现的时候,我们需要解决一些关于调用服务的问题:
-
使用容器技术,IP地址被动态分配给服务实例。每次地址更改时,使用者服务可能会中断,并需要手动更改。
-
每个服务URL都必须被使用者记住并成为紧密耦合的。
那么消费者或路由器如何知道所有可用的服务实例和位置呢?
解决方案