热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

5.微服务的事件驱动管理@微服务的设计与实现

5.微服务的事件驱动管理这是本电子书的第五章,内容涉及使用微服务构建应用程序。第一章介绍了微服务架构模式,并讨论了使用微服务的优点和缺点。第二章和第三
5. 微服务的事件驱动管理

这是本电子书的第五章,内容涉及使用微服务构建应用程序。第一章介绍了微服务架构模式,并讨论了使用微服务的优点和缺点。第二章和第三章描述了微服务架构内部通信的不同方面。第四章探索了服务发现紧密相关的问题。在这章,我们换个角度,看看微服务架构中出现的分布式数据管理问题。

微服务和分布式数据管理的问题

整体式应用程序通常具有单个关系数据库。使用关系型数据库的关键好处是,您的应用程序可以使用 ACID 事务, 这提供了一些重要的保证:

  • 原子性 :以原子方式进行更改
  • 一致性 : 数据库的状态始终保持一致
  • 隔离 :即使事务是并发执行的,它们似乎也是按顺序执行的。
  • 持久性:一旦事务已提交,它就不会被撤消。

因此,您的应用程序可以简单地开始一个事务,更改(插入、更新和删除)多行,然后提交事务。

使用关系数据库的另一大好处是它提供了SQL, 它是一种丰富的,声明式的,标准的查询语言。您可以轻松编写组合来自多个表的数据的查询。然后,RDBMS 查询计划程序确定执行查询的最佳方式。您不必担心如何访问数据库之类的低级细节。而且,由于应用程序的所有数据都位于一个数据库中,因此很容易查询。

不幸的是,当我们移到微服务架构中是,数据访问变得更加的复杂。这是因为每个微服务都有自己的数据,并且数据堆微服务是私有的。并且只能够通过他的API访问。封装这些数据以确保微服务是松耦合的,并且能够独立于其他微服务演进。如果多个微服务访问同样的数据,表结构更新需要耗时,协调所有服务。

更糟糕的是,不同的微服务经常使用不同种类的数据库。现代应用程序存储和处理各种类型的数据。并且关系型数据库并非一直是最好的选择。在一些使用场景下,一个特定的nosql数据库可能具有更方便的数据模型,并提供更好的性能和可伸缩性。例如,对于存储和查询文本的服务来说,使用文本搜索引擎(如 Elasticsearch)是有意义的。同样,存储社交图谱数据的服务可能应该使用图数据库,例如Neo4j。基于微服务的应用程序通常混合使用SQL和NoSQL数据库,即所谓的多语言持久性方法。

用于数据存储的分区、多语言持久性体系结构具有许多优点,包括松散耦合的服务以及更好的性能和可伸缩性。但是,它确实引入了分布式数据管理的一些挑战。

第一个挑战是如何实现跨多个服务时,保持一致性的业务事务。看看为什么这是一个问题, 让我们看一下在线B2B商店的示例。客户服务(Customer Service)维护客户的信息,包括他们的信用额度。订单服务(Order Service)管理订单,并且必须验证一个新的订单不违反客户的信用额度。在此应用程序的整体版本中,订单服务可以简单地使用 ACID 事务来检查可用信用额度并创建订单。

相比之下,在微服务体系结构中,ORDER 和 CUSTOMER 表对各自的服务是私有的,如图 5-1 所示。

在这里插入图片描述

订单服务并不能够直接访问客户表。它只能使用客户服务提供的API。订单服务可能会使用分布式事务,称为两阶段提交(2PC:two-phase commit)。但是,在现代应用中,2PC通常不是一个可行的选择。CAP 原理要求你在可用和 ACID-风格 一致性之间做出选择,例如大多数NoSQL 数据库,并不支持 2PC. 跨服务和数据库保持数据一致性至关重要,因此我们需要另一种解决方案。

第二个调整是如何实现查询,这个查询要从多个服务获取数据。例如,让我们想想一下应用程序需要显示一个客户和他最近的订单。如果订单服务提供一个API,用于检索一个客户的订单。然后,您可以使用应用程序端联接检索此数据。应用程序从客服服务中检索客户,并从订单服务中检索客户的订单。然而,假设,订单服务值支持根据主键查询订单(可能他使用了一个NoSQL数据库,只支持基于主键的检索)。在这种情况下,没有明显的方法来检索需要的数据。

基于事件驱动的架构(Event-Driven Architecture)

对于许多应用程序,解决方法是使用基于事件驱动的架构(event-driven architecture)。在这个架构中,微服务在发生值得注意的事情时发布事件。例如,当它更新业务实体时。其他的微服务订阅这些事件。当一个微服务收到一个事件时,他可以更新他自己的业务实体,这可能导致发布更多的事件。

你可以使用事件来实现跨多个服务的事务。一个事务包含一系列的步骤。每个步骤包含一个微服务更新一个业务主题,并发布一个事件,这个时间触发下一个步骤。下面的时序图显示了在创建一个订单的时候,你可以如何使用一个基于时间驱动的方法来检查信用卡是否可用。

微服务通过消息中间件交换事件:

  • 订单服务创建一个状态为 NEW 的订单,并发布一个订单创建事件。

在这里插入图片描述

  • 客户服务消费这个订单创建事件,为订单保留信用额度,并发布"信用额度保留"事件。

在这里插入图片描述

  • 订单服务消费"信用额度保留"事件,并将订单的状态更改为OPEN。

在这里插入图片描述

一个更复杂的场景可能涉及更多的步骤,例如在客户信用卡检索的同时,检索库存。

如果(a)每个服务以原子方式更新数据库并发布一个事件(稍后会详细介绍),并且(b) Message Broker 保证事件至少传递一次,那么您就可以实现跨多个服务的业务事务。重要的是要注意这些不是 ACID 事务。它们提供的保证要弱得多,例如最终的一致性。此事务模型称为 BASE 模型。

您可以使用事件来维护预联接多个微服务拥有的数据的具体化视图。维护视图的服务订阅相关事件并更新视图。图5-5 描述客户订单视图更新程序服务,该服务根据客户服务和订单服务发布的事件更新客户订单视图。

在这里插入图片描述

当这个客户订单视图更新服务收到一个客户或者订单时间,他更新这个客户订单视图数据存储。你可使用一个文档数据库,比如MongoDB,为每个客户存储一个文档,来实现客户订单视图。客户订单视图查询服务处理一个客户和最近的订单请求,通过查询客户订单视图数据库。

一个事件驱动结构有多个好处和缺点。它支持实现跨多个服务并提供最终一致性的事务。另一个好处是,它还使应用程序能够维护物质化视图(materialized views)。

这种编程模型的一个缺点是,它比使用ACID事务更加的复杂。通常,您必须实施补偿事务才能从应用程序级故障中恢复。例如,如果信用卡检查失败,你必须取消一个订单。同样,应用程序必须处理不一致的数据。这是因为正在进行的事务所做的更改是可见的。如果应用程序从尚未更新的具体化视图中读取,则还可以看到不一致之处。另一个缺点是订阅者必须检测并忽略重复事件。

实现原子性(Achieving Atomicity)

在一个基于时间驱动的架构中,也会有自动更新数据库和发布时间的问题。例如,订单服务必须在 ORDER 表中插入一条数据,然后发送一个订单创建事件。这两个操作必须以原子方式完成。如果在更新完数据库后服务崩溃了,但还没有发布这个事件。系统变诶不一致。确保原子性的标准方法是使用涉及数据库和消息代理的分布式事务。然而,由于上述原因,例如CAP定理,这正是我们不想做的事情。

使用本地事务发布事件(Publishing Events Using Local Transactions)

实现自动通信的一种方法是让应用程序使用仅涉及本地事务的多步骤过程发布事件。诀窍是有一个事件(EVENT)表, 它的功能是充当消息队列,在这个数据库里面存储了消息实体的状态。这个应用开始一个本地数据库事务,更新业务实体的状态,插入一个事件到事件(EVENT)表里面,发布事件到消息中间件(Message Broker), 然后使用一个本地的事务来标记事件已经发布了。图5-6显示了这种设计。

在这里插入图片描述

订单服务插入一条数据到订单(ORDER)表里面,事件发布者线程或进程在 EVENT 表中查询未发布的事件,发布事件,然后更新事件(EVENT)表,来标记事件已经发布了。

这个方法有一些优点和缺点。一个好处是,它保证在不依赖于2PC(2阶段提交)的情况下为每次更新发布事件。此外,应用程序还会发布业务级事件,从而消除了推送这些事件需求。这种方法的一个缺点是,它可能容易出错,因为开发人员必须记得发布事件。这种方法的局限性在于,由于某些NoSQL数据库事务和查询功能的限制,因此在使用这类数据库时实现起来具有挑战性。

这个方法通过应用程序使用本地事务来更新事务的状态,发布事务。就消除了对二阶段步骤(2PC)的依赖。让我们现在看一下这个方法,通过应用程序简单的更新状态来实现原子性。

挖掘数据库事务日志(Mining a Database Transaction Log)

不使用2PC实现原子性的另一种方法是,由挖掘数据库事务或提交日志的线程或进程发布事件。应用程序更新数据库,所有变更记录在了数据库的传输日志里。事务日志挖掘线程或进程读取事务日志并将事件发布到消息代理(Message Broker)。图5-7显示了这种设计.

在这里插入图片描述

这个方法的另外一个例子是开源的 LinkedIn Databus 项目。数据总线挖掘 oracle 事务日志并发布与更改相对应的事件。LinkedIn使用Databus来保持各种派生数据存储与系统记录一致。

另一个例子是AWS DynamoDB中的流机制,它是一个管理的 NoSQL 数据库。DynamoDB流包含在过去24小时内对DynamoDB表中的项进行更改(创建、更新和删除操作)的按时间顺序的序列。一个应用程序可以从流中读取这些变更,并且,例如,发布这些事件。

事务日志挖掘有各种优点和缺点。一个好处是他在不使用 2PC 的情况下,为每次更新都发布了事件。事务日志挖掘也能简化应用程序,通过从应用程序的业务逻辑中分离事件发布。一个主要的缺点是,事务日志的格式是每个数据库专有的,甚至可以在不同的数据库版本之间更改。同样,从事务日志中记录的底层更新到工程顶层业务事件可能很困难。

传输日志的挖掘,通过让应用程序来做数据库的更新来消除对2PC的依赖。现在让我们看看另一种消除更新并仅依赖于事件的方法。

使用事件源

事件源通过使用一种完全不同的、以事件为中心的方法来持久化业务实体,从而在不使用2PC的情况下实现原子性。应用程序不存储实体的当前状态,而是存储一系列状态更改事件。当业务实体的状态发生变化时。一个新事件被添加到事件列表中。因为保存事件是一个单一操作,所以它本质上是原子的。

要了解事件源是如何工作的,可以考虑将订单实体作为一个示例。在传统方法中,每个订单映射到order表中的一行,并映射到其中的行。例如,一个ORDER_LINE_ITEM表。

但是当使用事件源,订单服务以其状态更改事件的形式存储订单: Created, Approved, Shipped, Cancelled. 每个事件都包含足够的数据来重建订单的状态。

在这里插入图片描述

事件持久化在事件存储中, 这是一个事件数据库。数据库有一个用于添加和检索实体事件的API。事件存储的行为也类似于我们前面描述的体系结构中的消息代理。它提供了一个允许服务订阅事件的API。事件存储将所有事件传递给所有感兴趣的订阅者。事件存储是事件驱动的微服务体系结构的支柱。

事件源有一个好处。它解决了实现事件驱动架构的一个关键问题,并使在状态改变时可靠地发布事件成为可能。因此,它解决了微服务体系结构中的数据一致性问题。另外,因为它持久化的是事件而不是域对象,所以它在很大程度上避免了对象关系阻抗不匹配问题。事件来源还提供了对业务实体所做更改的100%可靠的审计日志,并使实现确定实体在任何时间点的状态的临时查询成为可能。事件来源的另一个主要好处是,您的业务逻辑由交换事件的松散耦合的业务实体组成。这使得从单一应用程序迁移到微服务体系结构要容易得多。

事件源也有一些缺点。它是一种不同的,并且不熟悉的编程风格。所以存在学习曲线。事件存储值支持通过主键直接查询业务实体。你必须使用命令行查询响应分离(CQRS)来实现查询。因此,应用程序必须最终处理一致的数据。

总结

在一个微服务架构中,每个微服务有他自己的私有数据库。不同的微服务可能使用不同的 SQL 和 NoSQL 数据库。虽然这种数据库架构具有显著的优点,但它也带来了一些分布式数据管理的挑战。第一个挑战是如何实现保持多个服务一致性的业务事务。第二个挑战是如何实现从多个服务检索数据的查询。

对于许多应用程序来说,解决方法是使用事件驱动架构(event-driven architecture). 实现事件驱动架构的挑战是如何自动更新状态,和如何发布事件。有几种方法可以实现这一点,包括使用数据库作为消息队列、事务日志挖掘和事件源。

Microservices in Action: NGINX and Storage Optimization

基于微服务方法的存储设计大量的和各种各样的数据存储,更复杂的是你如何访问和更新数据,在保持数据一致性上,给开发和运维带来了巨大的挑战。NGINX 为这类数据管理提供了关键的支持,主要体现在三个方面:

  1. 数据的缓存和微缓存, 使用NGINX缓存静态文件和微缓存应用程序生成的内容可以减少应用程序的负载,提高性能并减少潜在的问题。
  2. 每个数据存储的灵活性和可伸缩性, 一旦你实现 NGINX 作为一个返现代理服务,您的应用程序在创建、调整大小、运行和调整数据存储服务器以满足不断变化的需求方面获得了很大的灵活性。当每个服务都有自己的数据存储时,这一点至关重要。
  3. 监控和管理微服务,包括数据服务, 随着数据服务器数量的增加,支持复杂操作变得至关重要,监控和管理工具也是如此。NGINX Plus为应用性能管理提供了内置的工具和接口(如 Data Dog、Dynatrace和New Relic)。

NGINX微服务参考体系结构的三个模型中包含了特定于微服务的数据管理的例子,为你自己的设计决策和实现提供了一个起点。


推荐阅读
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 从0到1搭建大数据平台
    从0到1搭建大数据平台 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 本文介绍 DB2 中的基本概念,重点解释事务单元(UOW)和事务的概念。事务单元是指作为单个原子操作执行的一个或多个 SQL 查询。 ... [详细]
  • EST:西湖大学鞠峰组污水厂病原菌与土著反硝化细菌是多重抗生素耐药基因的活跃表达者...
    点击蓝字关注我们编译:祝新宇校稿:鞠峰、袁凌论文ID原名:PathogenicandIndigenousDenitrifyingBacte ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 在什么情况下MySQL的可重复读隔离级别会导致幻读现象? ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 本文详细介绍了在MySQL中如何高效利用EXPLAIN命令进行查询优化。通过实例解析和步骤说明,文章旨在帮助读者深入理解EXPLAIN命令的工作原理及其在性能调优中的应用,内容通俗易懂且结构清晰,适合各水平的数据库管理员和技术人员参考学习。 ... [详细]
  • ### 优化后的摘要本学习指南旨在帮助读者全面掌握 Bootstrap 前端框架的核心知识点与实战技巧。内容涵盖基础入门、核心功能和高级应用。第一章通过一个简单的“Hello World”示例,介绍 Bootstrap 的基本用法和快速上手方法。第二章深入探讨 Bootstrap 与 JSP 集成的细节,揭示两者结合的优势和应用场景。第三章则进一步讲解 Bootstrap 的高级特性,如响应式设计和组件定制,为开发者提供全方位的技术支持。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
author-avatar
mobiledu2502896807
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有