前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >事件驱动的微服务数据管理

事件驱动的微服务数据管理

作者头像
用户1263954
发布2018-01-30 15:36:22
1.6K0
发布2018-01-30 15:36:22
举报
文章被收录于专栏:IT技术精选文摘IT技术精选文摘

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

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

原子性 - 原子性变化

一致性 - 数据库的状态总是一致的

隔离 ----即使并发执行事务,它似乎是连续执行的

持久性 - 一旦交易已经提交,它不会被撤销

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

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

不幸的是,当我们转向微服务架构时,数据访问变得复杂得多。这是因为每个微服务拥有的数据对该微服务是私有的,只能通过其API访问。封装数据可确保微服务松散耦合,并可彼此独立发展。如果多个服务访问相同的数据,模式更新需要对所有服务进行耗时协调的更新。

更糟糕的是,不同的微服务经常使用不同类型的数据库。现代应用程序使用关系数据库来存储和处理各种数据并不总是最佳选择。对于某些用例,特定的NoSQL数据库可能具有更方便的数据模型,并提供更好的性能和可扩展性。例如,存储和查询文本以使用文本搜索引擎(如Elasticsearch)的服务是有意义的。类似地,存储社交图数据的服务应该可以使用图数据库,例如Neo4j。因此,基于微服务的应用程序通常使用SQL和NoSQL数据库的混合,所谓的通晓的持久化方法。

对数据存储的分区,通晓的持久性架构具有许多好处,包括松散耦合的服务以及更好的性能和可扩展性。 然而,它确实引入了一些分布式数据管理的挑战。

第一个挑战是如何实现维护多个服务之间一致性的事务。 要了解为什么这是一个问题,让我们来看一个在线B2B商店的例子。 客户服务部维护有关客户的信息,包括信用额度。 订单服务管理订单,并且必须验证新订单不超过客户的信用额度。 在此应用程序的整体版本中,订单服务可以简单地使用ACID交易来检查可用信用额度并创建订单。

相比之下,在微服务架构中,ORDER和CUSTOMER表对其各自的服务是私有的,如下图所示。

订单服务无法直接访问CUSTOMER表。它只能使用客户服务提供的API。订单服务可使用称为两阶段提交(2PC)的分布式事务。然而,2PC在现代应用中通常不是一个可行的选择。 CAP定理要求您在可用性和ACID风格的一致性之间进行选择,而可用性通常是更好的选择。此外,许多现代技术,如大多数NoSQL数据库,都不支持2PC。维护服务和数据库之间的数据一致性至关重要,因此我们需要另一种解决方案

第二个挑战是如何实现从多个服务中检索数据的查询。例如,我们假设应用程序需要显示客户和他最近的订单。如果订单服务提供了用于检索客户订单的API,那么您可以使用应用程序端连接来检索此数据。应用程序从客户服务中检索客户,并从订单服务中检索客户的订单。但是,假设订单服务仅支持按主键查找订单(可能使用仅支持基于主键检索的NoSQL数据库)。在这种情况下,没有显式的方法来检索所需的数据。

事件驱动的架构

对于许多应用,解决方案是使用事件驱动架构。 在这种体系结构中,一个微服务会发生一些事件,当事情发生时,例如更新业务实体时。 其他微服务订阅这些事件。 当微服务收到事件时,它可以更新自己的业务实体,这可能导致更多的事件被发布。

您可以使用事件来实现跨多个服务的业务事务。 交易由一系列步骤组成。 每个步骤包括更新业务实体的微服务,并发布触发下一步骤的事件。 以下的图表顺序显示了如何在创建订单时使用事件驱动的方法来检查可用信用。 微服务通过Message Broker交换事件。

  1. 订单服务创建状态为NEW的订单,并发布订单创建事件。
  1. 客户服务消费“订单创建”事件,为订单预留信用额度,并发布信用保留事件。
  1. 订单服务消费信用保留事件,并将订单的状态更改为OPEN。

更复杂的情况可能涉及额外的步骤,例如在检查客户信用的同时保留库存。

假设(a)每个服务原子上更新数据库并发布一个事件 - 稍后再更新 - (b)Message Broker保证事件至少传递一次,然后可以实现跨多个服务的业务事务。 重要的是要注意,这些不是ACID事务。 他们提供了更弱的保证,如最终的一致性。 此交易模型已被称为BASE模型。

您还可以使用事件来维护预先加入多个微服务所拥有的数据的物化视图。 维护视图的服务订阅相关事件并更新视图。 例如,维护客户订单视图的客户订单查看,更新程序服务订阅由客户服务和订单服务发布的事件。

当客户订单查询更新服务接收到Customer或Order事件时,它会更新Customer Order视图数据存储。您可以使用诸如MongoDB的文档数据库来实施客户订单视图,并为每个客户存储一个文档。客户订单查询服务通过查询客户订单来查看数据存储处理过的客户请求和最近的订单。

事件驱动的架构有几个好处和缺点。它能够实现跨越多个服务并提供最终一致性的事务。另一个好处是它还使应用程序能够维护物化视图。一个缺点是编程模型比使用ACID事务时更复杂。通常,您必须实施补偿交易以从应用程序级别的故障中恢复;例如,如果信用检查失败,您必须取消订单。此外,应用程序必须处理不一致的数据。那是因为飞行交易所做的更改是可见的。如果从实例化视图读取尚未更新的应用程序,也可以看到不一致。另一个缺点是用户必须检测并忽略重复的事件。

实现原子性

在事件驱动架构中,还存在原子更新数据库和发布事件的问题。例如,订单服务必须在ORDER表中插入一行,并发布Order Created事件。这两个操作必须原子地完成。如果在更新数据库后但在发布事件之前服务崩溃,系统将不一致。确保原子性的标准方法是使用涉及数据库和Message Broker的分布式事务。然而,由于上述原因,如CAP定理,这正是我们不想做的。

使用本地事务发布事件

实现原子性的一种方法是应用程序使用仅涉及本地事务的多步骤过程来发布事件。诀窍是在存储业务实体状态的数据库中设置一个作为消息队列的EVENT表。应用程序开始(本地)数据库事务,更新业务实体的状态,将事件插入到EVENT表中,并提交事务。单独的应用程序线程或进程查询EVENT表,将事件发布到Message Broker,然后使用本地事务将事件标记为已发布。下图显示了设计。

订单服务将一行插入到ORDER表中,并将一个Order Created事件插入到EVENT表中。事件发布者线程或进程向EVENT表查询未发布的事件,发布事件,然后更新EVENT表以将事件标记为已发布。

这种方法有几个好处和缺点。一个好处是它保证每个更新发布一个事件,而不依赖于2PC。此外,应用程序发布业务级事件,这消除了推断它们的需要。这种方法的一个缺点是,由于开发人员必须记住发布事件,因此可能会出错。这种方法的局限性在于,由于其有限的事务和查询功能,在使用某些NoSQL数据库时实现这一挑战。

该方法通过使应用程序使用本地事务更新状态和发布事件来消除对2PC的需要。现在我们来看一下通过使应用程序简单更新状态来实现原子性的方法。

挖掘数据库事务日志

没有2PC实现原子性的另一种方法是使事件由线程或进程发布,该线程或进程挖掘数据库的事务或提交日志。 应用程序更新数据库,从而导致更改记录在数据库的事务日志中。 事务日志Miner线程或进程读取事务日志并向Message Broker发布事件。 下图显示了设计。

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

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

事务日志挖掘有各种好处和缺点。一个好处是它保证每个更新发布一个事件,而不使用2PC。事务日志挖掘还可以通过将事件发布与应用程序的业务逻辑分开来简化应用程序。一个主要的缺点是事务日志的格式对每个数据库是专有的,甚至可以在数据库版本之间进行更改。此外,从事务日志中记录的低级更新可能难以对高级业务事件进行逆向工程。

事务日志挖掘消除了通过使应用程序做一件事情需要2PC:更新数据库。现在我们来看看一种不同的方法来消除更新并仅仅依赖于事件。

使用事件溯源

事件溯源通过使用完全不同的以事件为中心的持续业务实体的方法来实现无2PC的原子性。应用程序不是存储实体的当前状态,而是存储一系列状态改变事件。应用程序通过重放事件来重建实体的当前状态。每当业务实体的状态发生变化时,都会在事件列表中附加一个新事件。因为保存事件是一个单一的操作,它是固有的原子。

要了解事件溯源的工作原理,请以订单实体为例。在传统方法中,每个订单都映射到ORDER表中的一行,例如映射到ORDER_LINE_ITEM表中的行。但是,在使用事件溯源时,订单服务将以其状态更改事件的形式存储订单:创建,批准,发货,已取消。每个事件包含足够的数据来重建Order的状态。

事件存储在事件数据库中。该商店具有用于添加和检索实体事件的API。事件存储还在我们之前描述的体系结构中类似于Message Broker。它提供了一个API,使服务能够订阅事件。事件商店向所有感兴趣的用户提供所有活动。事件存储是事件驱动的微服务架构的支柱。

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

事件溯源也有一些缺点。它是一种不同而不熟悉的编程风格,因此有一个学习曲线。事件存储仅直接支持通过主键查找业务实体。您必须使用命令查询责任分隔(CQRS)来实现查询。因此,应用程序必须处理最终一致的数据。

总结

在微服务架构中,每个微服务都有自己的私有数据存储。不同的微服务可能会使用不同的SQL和NoSQL数据库。虽然这种数据库架构具有显着的优势,但它创造了一些分布式数据管理的挑战,第一个挑战是如何实现维护多个服务之间一致性的业务事务。第二个挑战是如何实现从多个服务中检索数据的查询。

对于许多应用,解决方案是使用事件驱动架构。实现事件驱动架构的一个挑战是如何以原子方式更新状态以及如何发布事件。有几种方法可以实现此目的,包括将数据库用作消息队列,事务日志挖掘和事件溯源。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT技术精选文摘 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档