在微服务中,每个服务是单个数据库还是单个数据库实例?


50

我了解微服务架构中的每个服务都应具有自己的数据库。但是,拥有自己的数据库,实际上是在同一个数据库实例中简单地拥有另一个数据库,还是在字面上拥有另一个数据库实例?

这样,我并不是说共享数据库,这是不对的,而是数据库实例。

例如,如果我使用的是AWS并具有3个服务,那么我是否要在单个RDS实例上为每个服务创建3个数据库,还是要创建3个RDS实例,每个实例都包含一个数据库,供3个服务分别使用?

如果在单个RDS实例上使用多个数据库是一个更好的主意,那么它会否决拥有独立服务的目的,因为:

  1. RDS实例的资源将在服务之间共享。在特定时间可能大量使用数据库的服务A是否会影响使用不同数据库但在同一RDS实例上的服务B?

  2. 所有服务将取决于该RDS实例上的数据库版本。


8
它最能满足您的特定要求。
罗伯特·哈维

1
我不确定是否会称自己为“微服务”专家,但是您可以采用任何方式进行设置和数据库。您可能有一个数据库,该数据库可由一种服务读取,而由另一种服务写入。或者,您整个系统只能有1 db(或从技术上来说,只有1 db)。
Mark Rogers

这是一本很好的读物:plainoldobjects.com/2015/09/02/…–
RandomUs1r

阅读有关“单一责任原则”的信息。您是否考虑过实现其他微服务使用的“数据库微服务”?
ChuckCottrill

Answers:


20

这实际上取决于您的可伸缩性要求,以及您的微服务实例如何/是否需要合作以提供单个结果。知道什么是权衡是有帮助的:

将其全部保存在一个数据库中

  • 简化配置
  • 无需与服务的其他实例进行协调或通信
  • 更容易发现您的完整数据集
  • 系统性能受数据库性能的限制

将数据库分开

  • 请求的完整答案可能分布在微服务实例之间
  • 在这种情况下,您需要增加沟通和协商来解决请求
  • 松开该微服务节点时处理数据(即使数据库仍在运行中,也要等到配置正确的新服务器备份后才能使用它)
  • 配置复杂性增加

您正在解决什么问题?

在某些情况下,您只担心短暂的数据。如果数据库出现故障,那不是什么大问题。在这些情况下,您甚至可能甚至不需要数据库。只需将所有内容保存在内存中,然后快速进行即可。这是最简单的解决方案。

在其他情况下,您需要数据完整性,但是数据库能够根据其拥有的节点数来扩展其容量。在这种情况下,单个数据库可能绰绰有余,并且独立管理其响应能力是正确的答案。

介于两者之间。例如,您可能具有区域特定的数据库,因此对于不同区域中的每个服务实例,您都有一个单独的数据库。通常,分片数据库的跨区域性能不佳,因此这是一种对数据进行局部定位并自己控制协调的方法。

原则与现实

我已经阅读了许多有关微服务及其模块化的文章。建议范围从将前端,微服务和数据层作为一个整体保持到共享所有实例的数据库和/或前端代码。通常,更多的隔离会提供最大的可伸缩性,但这是以增加复杂性为代价的。

如果您的微服务计算量很大,则可以根据需要允许这些微服务的数量扩展-共享数据库甚至前端代码都不会伤害或阻碍这种方法。

现实情况是,项目的特定需求将需要一系列不同的折衷方案,以便及时完成工作并处理您正在测量的系统负载(以及更多)。将完全隔离的前端,微服务和数据层三者视为崇高的目标。对系统的需求越多,您可能需要越接近该目标。我们还不是所有人[insert name of highly successful web entity here],他们并没有从现在开始。有时,您只需要从一个不太理想的情况开始,并对此感到满意。


71

假设您有一些服务可以使用相同类型的数据库系统和版本,如果您使用不同的数据库或数据库实例,则无需在设计时就做出决定。相反,您应该能够在部署时做出决定,只需配置即可。将您的服务设计为与其他服务的数据库的托管位置无关。

在操作过程中,您可以从一个实例开始,如果系统运行良好,请保持这种状态。但是,如果您注意到这对于您的系统来说扩展性不佳,因为一个实例上的不同数据库共享太多的资源,那么您总是可以选择使用不同的实例(如果有帮助)。

因此,一项服务不会违反微服务体系结构,仅仅是因为您让它们中的两个共享某些资源就可以了,而当共享资源成为强制性条件时,它就违反了它。


这种声音听起来像是过早的优化。如果消耗的资源永远不值得额外的实例怎么办?然后,您就浪费了时间来提高灵活性
reggaeguitar

5
@reggaeguitar:这样做的成本通常应该可以忽略不计-实际上,对于微服务体系结构而言,尝试在不同服务之间集中数据库配置可能比保持每个服务的db位置可单独配置要付出更多的努力。而且,微服务体系结构的全部重点是高可伸缩性,如果不需要的话,则不应首先对微服务做出决定。
布朗

1
@DocBrown很有道理,感谢您的回复!
reggaeguitar

13

没关系

从理论上讲,唯一重要的情况是一项服务是否需要迁移到数据库的不同版本。但是即使那样,从一开始就拥有单独的实例与将该服务从共享实例迁移到单独的实例之间并没有真正的区别。我实际上是说,仅由于这种情况而具有单独的实例是YAGNI的一个示例。


1
假设某个特定服务在单个RDS实例上使用率很高,是否最终会耗尽该实例上的资源并影响使用同一RDS实例的其他服务?

1
@xenon:是的,但这是考虑通过调整,更好的硬件或群集来提高RDS性能的原因,而不是考虑更改系统体系结构的原因-如果该服务为其他服务留出了容量,那么它将很快用尽容量全部靠自己。尽管我猜您可能有一个特殊要求,那就是过载的服务一定不能影响其他服务。实际上,某些RDS仍然可以通过基于用户定义资源上限来在单个实例上允许这样做。
Michael Borgwardt

重要的场景是微服务实例具有其自己的状态。然后,应使用自己的实例数据库进行部署,这也可能是性能瓶颈
Ewan

3

RDS实例是一个盒子。如果您在单个实例上有多个数据库,则它们共享CPU /内存等。

如果您的微服务性能受到其数据库性能的限制:则部署微服务的多个副本,每个副本使用不同的数据库,但每个数据库都位于同一RDS实例上。没有意义*(故障转移除外)。您的微服务集群将以与单个微服务相同的速度运行

但是,我会说受数据库性能约束的微服务是不寻常的。

通常,您的微服务将从数据库获取数据,执行一些逻辑并将一些信息写回到数据库。性能瓶颈是逻辑,而不是选择和/或插入。

在这种情况下,您只需在所有微服务实例之间共享同一数据库


我不得不质疑您的断言,逻辑是瓶颈,而不是数据库。以我的经验,最可能发现性能改进的地方是数据库。
RubberDuck

嗯,是的,但是可以肯定的是,这些性能的提高是通过将逻辑移出数据库并移入服务来实现的。一旦完成此操作,那么逻辑就是瓶颈
Ewan

1
通常没有。这些改进来自调整索引和查询。
RubberDuck

好吧,根据我的经验,这属于不寻常的情况。并不是说这些改进通常没有余地,但是在删除了所有真正不好的东西之后,数据库仍然是限制因素。
伊万

1

保持数据库对服务私有的目标是封装。您的微服务是一个黑匣子,系统中的其他服务将通过公共接口使用它。

此封装在两个平面上运行:

  • 第一个是逻辑的,在应用程序级别。您的服务在您的系统中拥有一些业务对象,并且需要保持有关这些对象的状态。一些特定的数据库支持这些业务对象只是实现细节。通过保留一个单独的数据库,可以防止其他服务对您的实现进行后门访问,从而迫使它们使用您的公共接口。这里的目标是简洁的体系结构和规范的编程。只要您的服务具有正确的连接详细信息以便可以找到它,数据库在此级别上的确切位置就无关紧要。

  • 第二级是可操作的。正如您指出的那样,即使您的设计是一个完美的黑匣子,位于一台机器上的不同工作也可能会争用资源。这是将单独的逻辑数据库放在单独的计算机上的一个很好的理由。正如其他答案所指出的那样,如果您的需求不是很苛刻并且预算紧张,则这是在单台计算机上托管的务实论据。但是,一如既往,需要权衡:随着系统的增长,此设置可能需要更多保姆。如果预算允许,我几乎总是喜欢使用两台单独的小型计算机来运行两项任务,而不是共享一台大型计算机。


1

我认为这可能在理论上有所帮助。微服务背后的动机之一是无共享,消息传递过程。微服务就像Actor模型中的actor。这意味着每个进程都维护自己的本地状态,并且一个进程访问另一个状态的唯一方法是发送消息(即使那样,另一个进程也可以响应,但是喜欢这些消息)。实际上,“每个微服务都有自己的数据库”的意思是,进程(即微服务)的状态是本地的私有的。在很大程度上,这表明应将“数据库” 并置微服务,即“数据库”应与微服务在同一逻辑节点上存储和执行。微服务的不同“实例”是单独的过程,因此每个应具有自己的“数据库”。

从这个角度来看,全局数据库或在微服务之间甚至微服务实例之间共享的数据库将构成共享状态。从微服务的角度来看,“适当”的处理方式是让共享数据库由“数据库”微服务介导。其他想要了解数据库内容的微服务会将消息发送到该“数据库微服务”。通常,这不会消除原始微服务对本地状态的需求(即每个微服务实例“数据库”)!变化之处在于该本地状态所代表的含义。与其存储“ User Sally是管理员”,不如存储“数据库微服务在五分钟前说'User Sally是管理员'”。换一种说法, 关于其他微服务的状态。

这样做的好处是每个微服务都是独立的。这使微服务成为故障的原子单位。您(大多数)不必担心处于部分功能状态的微服务。当然,问题已经转移到微服务网络。由于无法联系其他微服务,微服务可能无法执行所需的功能。但是,好处是微服务将处于定义良好的状态,并且可能能够提供降级或有限的服务,例如通过解决过时的信念。缺点是很难获得整个系统的一致快照,并且可能有很多(不需要的)冗余和重复。

当然,建议不要将Oracle实例粘贴到每个Docker容器中。首先,并不是每个微服务都需要一个“数据库”。一些进程不需要任何持久状态即可正常工作。例如,在两种协议之间转换的微服务不一定需要任何持久状态。对于需要持久状态的情况,单词“数据库”仅表示“持久状态”。它可以是其中带有JSON的文件,也可以是Sqlite数据库,也可以是Oracle的本地运行副本,也可以是任何其他本地方式持久存储数据。如果“数据库”不是本地的,那么从纯微服务的角度来看,应将其视为单独的(微)服务。为此,让RDS实例成为微服务的“数据库”毫无意义。同样,这种观点不是“一堆带有自己的RDS数据库的微服务”,而是“一堆 RDS数据库通信的微服务”。此时,数据是否存储在同一数据库实例中没有区别。

在实用上,微服务体系结构增加了大量的复杂性。这种复杂性只是认真处理部分故障的代价。对于许多人来说,过大的杀伤力很可能不值得这样做。您应该以最有利的方式随意构建系统。对简单性和效率的担忧很可能导致偏离纯微服务架构。代价将是额外的耦合,这会引入自身的复杂性,例如服务之间的无形交互以及对您自由部署和扩展的限制。


“由于无法联系其他微服务。” -我以为微服务永远不应该联系其他微服务?
Marc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.