「微服务架构」跨多个微服务的数据架构模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「微服务架构」跨多个微服务的数据架构模式相关的知识,希望对你有一定的参考价值。

参考技术A

在微服务中,一个逻辑上原子操作可以经常跨越多个微服务。即使是单片系统也可能使用多个数据库或消息传递解决方案。使用多个独立的数据存储解决方案,如果其中一个分布式流程参与者出现故障,我们就会面临数据不一致的风险 - 例如在未下订单的情况下向客户收费或未通知客户订单成功。在本文中,我想分享一些我为使微服务之间的数据最终保持一致而学到的技术。

为什么实现这一目标如此具有挑战性?只要我们有多个存储数据的地方(不在单个数据库中),就不能自动解决一致性问题,工程师在设计系统时需要注意一致性。 目前,在我看来,业界还没有一个广为人知的解决方案,可以在多个不同的数据源中自动更新数据 - 我们可能不应该等待很快就能获得一个。

以自动且无障碍的方式解决该问题的一种尝试是实现两阶段提交(2PC)模式的XA协议。但在现代高规模应用中(特别是在云环境中),2PC似乎表现不佳。为了消除2PC的缺点,我们必须交易ACID for BASE并根据要求以不同方式覆盖一致性问题。

在多个微服务中处理一致性问题的最着名的方法是Saga模式。 您可以将Sagas视为多个事务的应用程序级分布式协调 。 根据用例和要求,您可以优化自己的Saga实施。 相反,XA协议试图涵盖所有场景。 Saga模式也不是新的。 它在过去已知并用于ESB和SOA体系结构中。 最后,它成功地转变为微服务世界。 跨越多个服务的每个原子业务操作可能包含技术级别的多个事务。 Saga Pattern的关键思想是 能够回滚其中一个单独的交易 。 众所周知,开箱即用的已经提交的单个事务无法进行回滚。 但这是通过引入 补偿操作来 实现的 - 通过引入“取消”操作。

除了 取消 之外,您还应该考虑使您的服务具有 幂等性 ,以便在出现故障时重试或重新启动某些操作。 应监控故障,并应积极主动地应对故障。

如果在进程的中间 负责调用补偿操作的系统崩溃或重新启动 ,该怎么办? 在这种情况下,用户可能会收到错误消息,并且应该触发补偿逻辑,或者 - 当处理异步用户请求时,应该恢复执行逻辑。

要查找崩溃的事务并恢复操作或应用补偿,我们需要协调来自多个服务的数据。 对账

是在金融领域工作的工程师所熟悉的技术。你有没有想过银行如何确保你的资金转移不会丢失,或者两个不同的银行之间如何汇款?快速回答是对账。

回到微服务,使用相同的原则,我们可以在一些 动作触发器 上协调来自多个服务的数据。当检测到故障时,可以按计划或由监控系统触发操作。最简单的方法是运行逐记录比较。可以通过 比较聚合值来 优化该过程。在这种情况下,其中一个系统将成为每条记录的真实来源。

想象一下多步骤交易。如何在对帐期间确定哪些事务可能已失败以及哪些步骤失败?一种解决方案是 检查每个事务的状态 。在某些情况下,此功能不可用(想象一下发送电子邮件或生成其他类型消息的无状态邮件服务)。在其他一些情况下,您可能希望立即了解事务状态,尤其是在具有许多步骤的复杂方案中。例如,预订航班,酒店和转机的多步订单。

在这些情况下,事件日志可以提供帮助。 记录是一种简单但功能强大的技术 许多分布式系统依赖于日志 。 “ 预写日志记录 ”是数据库在内部实现事务行为或维护副本之间一致性的方式。相同的技术可以应用于微服务设计。在进行实际数据更改之前,服务会写入有关其进行更改的意图的日志条目。实际上, 事件日志可以是协调服务所拥有的数据库中的表或集合

事件日志不仅可用于 恢复事务处理 ,还可用于为系统用户,客户或支持团队提供 可见性 。但是,在简单方案中,服务日志可能是冗余的, 状态端点或状态字段 就足够了。

到目前为止,您可能认为sagas只是编配(orchestration )方案的一部分。但是sagas也可以用于编排(choreography ),每个微服务只知道过程的一部分。 Sagas包括处理分布式事务的正流和负流的知识。在编排(choreography )中,每个分布式事务参与者都具有这种知识。

到目前为止描述的一致性解决方案并不容易。他们确实很复杂。但有一种更简单的方法: 一次修改一个数据源 。我们可以将这两个步骤分开,而不是改变服务的状态并在一个过程中发出事件。

在主要业务操作中,我们修改自己的服务状态,而单独的进程可靠地捕获更改并生成事件。这种技术称为变更数据捕获(CDC)。实现此方法的一些技术是Kafka Connect或Debezium。

但是,有时候不需要特定的框架。一些数据库提供了一种友好的方式来拖尾其操作日志,例如MongoDB Oplog。如果数据库中没有此类功能,则可以通过时间戳轮询更改,或使用上次处理的不可变记录ID查询更改。避免不一致的关键是使数据更改通知成为一个单独的过程。在这种情况下,数据库记录是 单一的事实来源 。只有在首先发生变化时才会捕获更改。

更改数据捕获的最大缺点是业务逻辑的分离。更改捕获过程很可能与更改逻辑本身分开存在于您的代码库中 - 这很不方便。最知名的变更数据捕获应用程序是与域无关的变更复制,例如与数据仓库共享数据。对于域事件,最好采用不同的机制,例如明确发送事件。

让我们来看看颠倒的单一事实来源。如果不是先写入数据库,而是先触发一个事件,然后与自己和其他服务共享。在这种情况下,事件成为事实的唯一来源。这将是一种事件源的形式,其中我们自己的服务状态有效地成为读取模型,并且每个事件都是写入模型。

“事件优先”方法面临的挑战也是CQRS本身的挑战。想象一下,在下订单之前,我们想要检查商品的可用性。如果两个实例同时收到同一项目的订单怎么办?两者都将同时检查读取模型中的库存并发出订单事件。如果没有某种覆盖方案,我们可能会遇到麻烦。

处理这些情况的常用方法是乐观并发:将读取模型版本放入事件中,如果读取模型已在消费者端更新,则在消费者端忽略它。另一种解决方案是使用悲观并发控制,例如在检查项目可用性时为项目创建锁定。

“事件优先”方法的另一个挑战是任何事件驱动架构的挑战 - 事件的顺序。多个并发消费者以错误的顺序处理事件可能会给我们带来另一种一致性问题,例如处理尚未创建的客户的订单。

诸如Kafka或AWS Kinesis之类的数据流解决方案可以保证将按顺序处理与单个实体相关的事件(例如,仅在创建用户之后为客户创建订单)。例如,在Kafka中,您可以按用户ID对主题进行分区,以便与单个用户相关的所有事件将由分配给该分区的单个使用者处理,从而允许按顺序处理它们。相反,在Message Brokers中,消息队列具有一个订单,但是多个并发消费者在给定顺序中进行消息处理(如果不是不可能的话)。在这种情况下,您可能会遇到并发问题。

实际上,在需要线性化的情况下或在具有许多数据约束的情况(例如唯一性检查)中,难以实现“事件优先”方法。但它在其他情况下确实很有用。但是,由于其异步性质,仍然需要解决并发和竞争条件的挑战。

有许多方法可以将系统拆分为多个服务。我们努力将单独的微服务与单独的域匹配。但域名有多细化?有时很难将域与子域或聚合根区分开来。没有简单的规则来定义您的微服务拆分。

虽然匹配帐户余额至关重要,但有许多用例,其中一致性不那么重要。想象一下,为分析或统计目的收集数据。即使我们从系统中随机丢失了10%的数据,也很可能不会影响分析的业务价值。

数据的原子更新需要两个不同系统之间达成共识,如果单个值为0或1则达成协议。当涉及到微服务时,它归结为两个参与者之间的一致性问题,并且所有实际解决方案都遵循一条经验法则:

在给定时刻,对于每个数据记录,您需要找到系统信任的数据源

事实的来源可能是事件,数据库或其中一项服务。实现微服务系统的一致性是开发人员的责任。我的方法如下:

微服务架构的设计模式

想象一下,将一个功能单元分解为多个小型服务单元。这正是微服务对传统单片架构的作用。但是,除此之外还有更多的东西。微服务是所有主要软件开发项目的首选解决方案。

但即使它有一个主要目的,但在整个过程中还存在一些需要解决的挑战。一方面设计了微服务架构,人们学习了几种微服务设计模式,这些模式不仅可以提高性能,还可以简化开发人员的生活。但在我们深入研究架构设计模式之前,让我们对成功的微服务架构基本基础进行抽象概述  

用于设计微服务架构的原理

  1. 高内聚力和松散耦合。

  2. 无缝的API集成。

  3. 每项服务的独特识别来源。

  4. 实时流量管理

  5. 最小化数据表以优化负载。

  6. 对外部和内部API执行持续监视。

  7. 每个微服务的隔离数据存储  - 这对于保持对数据的有限访问和避免“服务耦合”非常重要。基于用户的数据分类很重要,可以通过命令和查询责任分离(CQRS)来实现。

  8. 权力下放 - 设计微服务架构的首要原则是能够将单片架构分解为单独的单个实体。这些实体称为微服务。这些微服务独立于其他系统功能而工作,所有用户都可以编辑,删除或使用任何功能,而不会影响系统性能。

  9. 可扩展性 - 微服务 的构建目标是:性能和效率。在现实世界的问题解决中,扩展和大规模系统对于任何微服务生态系统的性能都至关重要。可伸缩性对于设计微服务架构至关重要。由于多个片段可能在多种技术上运行,因此处理大量数据可能是一项挑战。但是,正确实现和使用  应用程序控制器  可以实现微服务架构的可扩展性。

  10. 通过DevOps集成持续交付 - 在DevOps中工作的人员通常很容易接受微服务架构,因为易于访问和集成多种技术。要设计微服务架构,需要关注提高系统的性能和效率。这促使DevOps更快地提供解决方案。与传统的单片设计相比,它还具有一定的优势,例如易于部署,可靠的解决方案,可扩展性和管理。因此,它构成了设计基本原则的主要部分。

但考虑到这些原则,需要克服某些挑战才能实现成功的微服务架构结构。这些障碍可能看起来很难,但是通过一系列微服务设计模式和正确的实现,实现同样的目标是可能的。我们来看看其中一些微服务设计模式。

用于有效协作的微服务设计模式

由于有如此多的微服务同时运行,协作成为运行高效微服务架构的必要条件。今天我们将看一下设计微服务的协作模式。

1.聚合器微服务设计模式

在涉及多个服务的情况下,获取输出并将其组合给最终用户是必要的。对于用户来组合数据,将需要对系统的巨大内部知识。在我们设计微服务架构时,分解整体意味着输出源的划分。因此,为了聚合这些数据,我们使用了聚合器模式。

该解决方案可以通过两个主要组件转发给最终用户。第一个是复合微服务,后面是API网关。它们中的任何一个都将聚合数据并将其转发给用户。但是,如果在分解系统时使用业务功能,则应首选复合微服务。

2.分支微服务设计模式


它们基本上扩展了聚合器设计模式。在分支微服务中,您可以同时处理来自2个独立或精确2个互斥的微服务链的请求和响应。

这种设计模式还可以灵活地根据您的业务需求召集单独的多个链甚至单个链。对于电子商务网站或Web应用程序,我们可能需要从属于不同微服务的多个源检索数据。这就是Branch Microservice Design Pattern发挥有效作用的地方。


3.前端/ API网关的后端

作为单一联系源的API网关不仅可以充当代理服务器来将请求路由到微服务,还可以聚合来自多个服务的结果并将输出发送给用户。它可以处理多个协议请求并在需要时进行转换。(例如,HTTPS到AMQP,反之亦然)

用于性能监控的微服务设计模式

监控性能是成功的微服务架构的一个重要方面。它有助于计算效率并了解可能会降低系统速度的任何缺点。请记住以下与可观察性相关的模式,以确保稳健的微服务架构设计。

1.日志聚合

当我们提到微服务架构时,我们指的是一个精致而精细的架构,其中一个应用程序包含许多微服务。这些微服务独立并同时运行,支持多种服务以及各种机器上的实例。每个服务都会在日志中生成有关其执行的条目。如何跟踪众多服务相关日志?这是日志聚合的步骤。作为防止混乱的最佳实践,您应该拥有主日志记录服务。此主日志记录服务应负责聚合来自所有微服务实例的日志。此集中日志应该是可搜索的,以便于监控。

2.综合监控又称语义监控

正如我之前解释的那样,对于成功的微服务架构而言,监控是一项痛苦但却不可或缺的任务。通过同时执行数百个服务,确定导致日志注册表失败的根区域变得很麻烦。综合监测提供了帮助。当您执行自动化测试时,合成监视有助于定期映射结果与生产环境进行比较。如果生成故障,用户将收到警报。使用语义监控,您可以使用单个箭头瞄准2件事

  • 监控自动化测试用例。

  • 根据业务需求检测生产故障。

3. API健康检查

微服务架构设计促进彼此独立的服务,以避免系统中的任何延迟。我们所知道的API是在线连接的构建块。必须定期对您的API进行健康检查,以实现任何障碍。经常观察到微服务已启动并运行但仍无法处理请求。这可能是由于许多因素造成的:

  • 服务器负载

  • 用户采用

  • 潜伏

  • 错误记录

  • 市场份额

  • 下载

为了克服这种情况,我们应该确保每个运行的服务都必须具有特定的运行状况检查API端点。例如:在每个服务结束时附加HTTP / health将返回相应服务实例的运行状况。服务注册表定期呼吁运行状况检查API端点执行运行状况扫描。健康检查将为您提供以下信息:

  1. 一种特定于您的应用程序的逻辑。

  2. 主持人的状态。

  3. 与其他基础结构或与任何服务实例的连接的连接的状态。

将这一切分解为业务能力

将单片架构“分解”为微服务的过程需要遵循某些参数。这些参数有不同的基础。今天我们将看看微服务设计模式的分解,这将留下持久的影响。

1.针对每种业务能力的独特微服务

微服务与高内聚和松耦合的组合一样成功。服务需要松散耦合,同时保持相似兴趣的功能。但是我们怎么做呢?我们如何将软件系统分解为更小的独立逻辑单元?
我们通过定义微服务的范围来支持特定的业务功能。

例如 -  
在每个组织中,有不同的部门合为一体。这些包括技术,营销,公关,销售,服务和维护。为了描绘微服务结构,这些不同的域将各自成为微服务,组织将成为系统。 
因此,库存管理负责所有库存。同样,航运管理部门将处理所有货件等。

为了保持效率并预见增长,最佳解决方案是使用业务功能分解系统。这包括分类到各个业务领域,这些领域负责在自己的能力中产生价值。

2.围绕类似业务能力的微服务

尽管在业务能力的基础上进行了隔离,但微服务通常会带来更大的挑战。服务中的常见课程怎么样?那么,分解这些被称为“上帝阶级”的类需要干预。例如,在电子商务系统的情况下,订单将是几个服务的共同点,例如订单号,订单管理,订单退货,订单交付等。为了解决这个问题,我们转向一个通用的微服务设计原则,称为域驱动设计(DDD)。

在域驱动设计中,我们使用子域。这些子域模型定义了功能范围,称为有界上下文。这个有界上下文是用于创建每个微服务的参数,从而克服了常见类的问题。

3.扼杀藤蔓图案

在讨论单片架构的分解时,我们经常错过将单片系统转换为设计微服务架构的难题。在不妨碍工作的情况下,转换可能非常困难。为了解决这个问题,我们有基于藤类比的扼杀者模式。以下是 Martin Fowler 所说的  Strangler模式的含义:

“这个地区的一个自然奇观[澳大利亚]是巨大的扼杀藤蔓。它们在无花果树的上部分枝上种子,逐渐沿着树下行,直到它们在土壤中生根。多年来,他们成长为奇妙而美丽的形状,同时扼杀并杀死了他们的主人树。“

对于Web应用程序,Strangler模式非常有用,可以将服务分解到不同的域中。由于呼叫来回,不同的服务存在于不同的域上。因此,这两个域存在于同一个URI上。一旦服务改革,它就  “扼杀”现有版本的应用程序。遵循该过程直到整体不存在。

用于优化数据库存储的微服务设计模式

对于  微服务架构,松耦合是一个基本原则。这实现了独立服务的部署和可扩展性。多个服务可能需要访问未存储在其单元中的数据。但由于耦合松散,访问这些数据可能是一个挑战。主要是因为不同的服务具有不同的存储要求,并且在微服务设计中对数据的访问受到限制。因此,我们根据不同的要求来看一些主要的数据库设计模式。

1.每个服务的单个数据库

通常应用于域驱动设计中,每个服务一个数据库将整个数据库表达为特定的微服务。由于挑战和缺乏可访问性,需要设计每个服务的单个数据库。这些数据只能由微服务访问。此数据库对任何外部微服务的访问权限都有限。其他人访问此数据的唯一方法是通过微服务API网关。

2.每个服务的共享数据库

在域驱动设计中,每个服务单独的数据库是可行的,但是在将单个体系结构分解为微服务的方法中,使用单个数据库可能很困难。因此,当分解过程继续进行时,建议为有限数量的服务实现共享数据库。此号码应限制为2或3项服务。此数字应保持较低,以允许部署,自治和可伸缩性。

3.事件采购设计模式

根据马丁福勒的说法

“ 事件源 ”  确保应用程序状态的所有更改都存储为一系列事件。我们不仅可以查询这些事件,还可以使用事件日志重建过去的状态,并作为自动调整状态以应对追溯更改的基础。

这里的问题在于可靠性。您如何依赖该体系结构进行更改或发布与应用程序状态更改相关的实时事件?
事件采购有助于通过在每次业务实体更改其状态时将新事件附加到事件列表来实现这种情况。像客户这样的实体可能包含许多事件。因此建议应用程序保存实体当前状态的屏幕截图以优化负载。

3.命令查询责任分离(CQRS)

在每服务数据库模型中,由于只能访问一个数据库,因此无法实现查询。对于查询,要求基于联合数据库系统。但是我们如何查询呢?

基于  CQRS,为了按服务模型查询单个数据库,应用程序应分为两部分:命令和查询。在此模型中,命令处理与创建,更新和删除相关的所有请求,同时通过物化视图处理查询。这些视图通过一系列事件进行更新。反过来,这些事件是使用事件源模式创建的,该模式标记数据的任何变化。这些变化最终成为事件。

无缝部署的微服务设计模式

当我们实施微服务时,在调用这些服务期间会出现某些问题。在设计微服务架构时,某些交叉模式可以简化工作。

1.服务发现

要解决此问题并向用户提供请求的位置,需要使用注册表。启动时,服务实例可以在注册表中注册并在关闭时取消注册。这使用户能够找到可以查询的确切位置。此外,注册表进行的运行状况检查将确保仅提供工作实例。这也提高了系统性能。

2.蓝绿部署

在微服务设计模式中,有多个微服务。无论何时实施更新或部署更新版本,都必须关闭所有服务。这导致巨大的停机时间,从而影响生产力。为避免此问题,在设计微服务架构时,应使用蓝绿色部署模式。

在这种模式中,两个相同的环境并行运行,称为蓝色和绿色。目前,其中只有一个是现场直播并处理所有生产流量。例如,蓝色是实时的并且处理所有流量。在新部署的情况下,将最新版本上载到绿色环境中,将路由器切换到相同的位置,从而实现更新。

用于性能监控的微服务设计模式

监控性能是成功的微服务架构的一个重要方面。它有助于计算效率并了解可能会降低系统速度的任何缺点。请记住以下与性能监视相关的模式,以确保稳健的微服务架构设计。

1.日志聚合

当我们提到微服务架构时,我们指的是一个精致而精细的架构,其中一个应用程序包含许多微服务。这些微服务独立并同时运行,支持多种服务以及各种机器上的实例。每个服务都会在日志中生成有关其执行的条目。如何跟踪众多服务相关日志?这是日志聚合的步骤。作为防止混乱的最佳实践,您应该拥有主日志记录服务。此主日志记录服务应负责聚合来自所有微服务实例的日志。此集中日志应该是可搜索的,以便于监控。

2.综合监控又称语义监控

随着负载和微服务的增加,对系统性能进行持续检查变得非常重要。这包括可能形成的任何模式或解决遇到的问题。但更重要的是,如何收集数据?

答案在于使用度量服务。此度量标准服务可以是Push表单,也可以是Pull表单。顾名思义,AppDynamics等推送服务将指标推送到服务,而普罗米修斯等Pull服务从服务中提取数据。

3.运行健康检查

微服务架构设计促进彼此独立的服务,以避免系统中的任何延迟。但是,有时系统启动并运行,但由于服务错误而无法处理事务。为了避免对这些错误服务的请求,必须实现负载平衡模式。

为实现这一目标,我们在每项服务结束时使用“/ health”。此检查用于查明服务的健康状况。它包括主机的状态,连接和算法逻辑。

结论

虽然并非所有的设计模式都适用于给定的微服务,但您可以放心,大多数设计模式将在任何地方使用。这些设计模式可帮助开发人员引入一致的标准,并为整个应用程序带来可靠性。

 这些设计模式的评估,审计,实施和  测试微服务是微服务架构的持续过程。从应用程序的设计阶段到生产的维护阶段,这些模式将始终有所帮助。

————————————————————

推荐阅读:








以上是关于「微服务架构」跨多个微服务的数据架构模式的主要内容,如果未能解决你的问题,请参考以下文章

微服务架构的分布式事务问题如何处理?

如何快速掌握分布式微服务架构体系?

响应式微服务架构-分布式系统设计原则

分布式微服务企业快速架构SpringCloud分布式微服务云架构快速开发平台源码

跨机房微服务高可用方案:DerbySoft路由服务设计与实现

为啥说分布式事务不再适用于微服务架构