每个人都知道,微服务架构具有许多优势,如可扩展性,易于维护和频繁的部署。但实施这些模式很棘手。您可能遇到的挑战之一是管理微服务数据库。服务如何存储数据而不会失去独立性?哪些微服务数据库模型选择基于云的应用程序?
在今天的博客中,我希望回答这些问题,我将向您解释我们如何管理微服务中的数据。大多数人正在从单体架构转移到微服务到分布式架构样式。大多数系统都使用单片架构风格。这很简单,你知道它很容易掌握,或多或少,他们正在使用一个数据库,因此大多数时候,这个数据库是一个RDMS(关系数据库管理系统)。
谈到关系数据库管理系统,我们有一个重要特征,是ACID。当您使用具有ACID属性的数据库时,您不需要担心数据,因为它使用ACID属性如此,数据库管理系统本身负责数据的一致性和合法性。
ACID代表,原子性,一致性,隔离和持续时间;
原子性:所有对数据的更改都是如同单次操作执行
一致性:当事务开始以及结束时,数据处于一致状态
隔离:交易的中间状态对其他交易是不可见的
耐用性:在事务成功完成后,即使在系统故障的情况下,数据持续更改并未撤消
当我们进入分布式架构或分布式数据库管理系统时,我们需要遵循的一个主要原则是CAP定理。现在在CAP定理有三个主要方面;
●一致性
●可用性
●分区容忍性
最重要的是,您可以在任何给定数据库中拥有这些方面中的两个。今天市场上没有数据库系统,可以满足单个数据库中的所有这三个方面。例如,当您关注传统的关系数据库时,您可以进行一致性和可用性。尽管如此,如果您正在使用一致性和分区容忍,MongoDB和Redis是您需要使用的数据库。同时,如果您正在使用可用性和分区容忍,您必须使用CouchDB或Cassandra。因此,您可以看到,您如何完全选择此数据库取决于您的业务需求或您正在尝试在您的分布式架构中实现的内容。
现在让我们进入微服务的世界。我已经看到,大多数微服务架构都使用反向代理或API网关来处理所有客户端请求。有一个独立的部署(Micro)服务集,但不幸的是,所有这些独立的微服务都连接到一个数据库。这是一个很好的做法吗?当然不是。
使用共享数据库具有微服务的问题:
●单点失败
●性能瓶颈
●服务依赖项
●不自主
因此,无论我们在此架构中的服务数量如何,我们只有单点故障:数据库,我们有许多性能瓶颈。每当他们想要进行数据查询或数据更新或与数据相关的任何相关的数据时,所有内容都会被瓶颈瓶颈,因此在此体系结构和服务依赖项中创建性能瓶颈。与此同时,由于我们在数据库上拥有的高依赖性,服务部署和更新不是自主。
自主权是微服务中的主要原则之一。您可以使用此类架构使用CICD Pipelines执行自主服务部署。它有挑战性,因为如果更改任何数据方面,它可能会影响许多其他微服务。由于数据库依赖项,您将无法独立部署到生产环境的情况下,而不会影响他人。
我们该怎么办?
我们可以做的最简单的事情是每个服务的单个数据库,或者只有少数依赖于特定数据库。
首先,我们可以拥有一个数据库服务器和逻辑分隔的数据库。
这个比我们所拥有的以前的架构风格更好,但仍然存在一些问题。它仍然有一个失败的点;因为我们在一个物理数据库中托管了逻辑分隔的数据库。它有一个嘈杂的邻居问题。例如,此红色微序具有在此特定数据库中运行的昂贵查询,因为它托管在一个数据库服务器中;此查询的性能影响可能会影响其他逻辑分隔的数据库。但这种架构风格中的一个加点之一是具有成本效益,因为我们不必支付不同的数据库实例。每当您尝试在基础架构(内部部署)上部署您的体系结构或数据库平台时,这种类型的模型是合适的。有了这个,您可以密切监视并继续无论存在问题所需的更改,这对微服务部署的内部内部有利。
要解决我们在上述架构中的问题,我们可以具有物理分离的数据库。由于所有这些数据库都有物理分离,因此一个特定数据库或任何其他故障的性能不会影响其他数据库。因此,每当您尝试实现这些服务之间的数据独立时,这种特定的架构都非常好。但是,这种模型的成本超过了单个数据库模型。
例如,假设您想要采取数据库许可证。在这种情况下,您必须购买所有这些数据库服务或服务器的许可证。每当您尝试在云上进行数据部署时,这是良好的,因为您不必在这种情况下维护昂贵的数据库服务器。这种架构的主要优点是数据独立性。
下一步
为了进一步分析这种微服务架构中的问题,让我们探索一个例子。让我们说有两种服务;
●订购的服务
●客户服务
因此,有一个查询进入订单服务,询问上周已在上周进行的顶级购买的名称。如果您认为以传统的数据库架构方式,我们可以在客户表和订单表之间加入。然而,在两个数据库分离的微服务体系结构中,我们无法在表之间加入。
解决此问题的另一种方式是通过获取客户ID,并将客户表单独查询来检索客户名称。但是,由于订单服务也取决于客户表,这是一个很大的不符合MicroService架构。因此,在任何微服务体系结构中都不建议这种交叉服务数据库调用。另一个解决方案是通过直接调用客户服务并说“嘿给我客户名称ID的名称或ID的客户名称”。然后我们可以检索此客户名称,这使得这是在两个微服务之间检索数据的最合适方式。
然而,这里还有另一个问题-延迟。一个解决方案是维护服务器端缓存。我们可以从服务器端缓存中的客户服务中摆脱数据库调用,但网络调用仍在存在。如果对客户表进行了任何更改,则更容易更新现金。此外,这有助于有效的内存管理,因为它位于服务器端。但是,网络电话仍在存在。
我们可以拥有的另一个解决方案是维护客户端缓存。在设计阶段,我们可以确定我们在客户服务订单服务中经常需要哪些数据元素,我们可以将它们上传或将这些数据视为客户端的缓存服务。
这种方法的优势在于没有网络呼叫。因此,在性能和弹性方面也存在明确的增益。例如,如果客户服务下跌,我们仍然可以在缓存中检索此数据,因此它不再依赖于客户服务。对于这种经常访问的数据,我们在这种方法中拥有的一个缺点是失效和更新问题。如果,已经在此客户表中进行了更改,更新此特定客户端缓存并不是简单的,这也不简单。
我们可以用于此数据分离的技术是什么?
执行此操作的最有效方法是使用CDC(更改数据捕获)工具。一个这样的例子是debezium。Debezium是我们可以使用的优秀CDC工具,它支持许多数据库平台。此工具允许我们浏览每项事务的数据库日志并触发事件。捕获数据更改后,您可以将该事件提升到消息代理或简单的队列中。订单服务中的此高速缓存服务可以订阅此事件流并相应更新缓存。
然而,这里有一个轻微的问题。在这里,我们必须考虑最终的一致性。我们不能认为,只要客户服务更新客户数据库中的任何内容,它就不会直接反映缓存。缓存需要一些时间来获得更新。这被称为最终的一致性,这是分布式数据管理的最重要方面之一。
数据报告方案
假设存在需要来自这两个服务的数据的报告服务。
让我们认为这项特定的报告查询需要1亿条记录。当此特定报告服务从主机服务本身检索数据时,它可能会影响主要的MicroService或订单服务的性能。因为上述报告服务正在要求100万条记录,因为其他要求也进入订单服务。因此它也影响了其他功能。
此方案有哪些可用的解决方案。以下是我们的问题;
高延迟
可能会影响其他事务处理器
需要在每份报告请求上获取数据
假设十个经理请求此报告十个不同的时间,我们需要执行此操作10次以生成报告。那么我们如何通过使用CDC工具更新诸如Kafka以通知所有更改和报告的消息代理来提供解决方案?报告服务可以缓存或保留在事件流中更新的数据。在此事件流中,您可以在报告服务需要时查询此数据。
您可以用于此事件流查询的一种这样的技术是ksqldb。因此,这一个与诸如Kafka流等事件流配对,并且您可以使用ksqdb查询所有这些事件流甚至事件源。它与其他常规SQL查询非常类似,但唯一的区别是而不是表,它是查询流处理。
单体到微服务数据迁移
大多数系统都是从巨石开始的,然后最终,当用户数量增加时,他们决定进入微服务。因此,我们可以在此处执行最简单的事情是为客户服务构建单独的微服务,并将所有数据元素或数据库移动到单独的数据库中,例如在客户数据库中。
但是,可能有含义。正如马丁福勒曾经说过的那样,“如果你做一个大爆炸重写,那么你保证的唯一是一个大爆炸”。我们不能在一夜之间进行这一点,因为移动数据比将代码逻辑移动到单独的微服务中更复杂。数据具有很高的依赖性,如果在移动后数据损坏,很难回去。因此,我们需要逐步规划这一行动。
>Image 9:Data and code migration using strangler-fig pattern
首先,我们需要创建一个API,在那里从中央数据库公开此客户数据,然后我们可以创建我们的客户服务以从此自定义API检索此数据。请记住,我们在中央数据库中拥有一切,我们可以创建客户数据库,然后我们可以使用CDC工具或任何其他ETL技术将此数据移动到客户数据库中。我们可以看到自定义API仍在那里,并且客户服务仍然获取用于数据检索的客户API。在这里,我们可以在这两个数据源之间具有一些临时灰度期或测试时段-来自API的数据,以及客户数据库中的数据是什么数据。因此,在运行这些测试后几周或几个月后,我们可以确保存在数据一致性。之后,我们最终可以摆脱此API和中央数据库。然后我们可以使用独立数据源具有独立的微服务。这是将数据移动到单独的微服务中的最佳方法。这也被称为陌生人适合模式,而在微服务迁移方面也是如此。
(本文由闻数起舞翻译自Using Travis CI Efficiently的文章《Managing Data in Microservices Architecture》,转载请注明出处,原文链接:
https://medium.com/geekculture/managing-data-in-microservices-architecture-fb459bdbf71f)