从另一个微服务“拥有”的数据库中读取数据为何如此糟糕


64

我最近阅读了有关微服务体系结构的出色文章:http : //www.infoq.com/articles/microservices-intro

它指出,当您在Amazon上加载网页时,则有100多个微服务合作提供该页面。

该文章描述了微服务之间的所有通信只能通过API。我的问题是,为什么这么糟糕的说法是所有数据库写操作只能通过API进行,但是您可以自由地直接从各种微服务的数据库中进行读取。例如,可以说微服务外部只能访问少数几个数据库视图,以便维护微服务的团队知道只要保持这些视图不变,那么他们就可以尽可能多地更改其微服务的数据库结构。想。

我在这里想念什么吗?还有其他原因为什么只能通过API读取数据?

不用说,我的公司要比亚马逊小得多(并且一直会这样),我们可以拥有的最大用户数约为500万。


答案中未提及的另一个普遍因素是,当写入数据库时​​,本地缓存,甚至是简单的O / R映射,在立即访问数据库时都可能会产生陈旧数据。如果您出于速度原因考虑绕过µservice API,则很可能是因为µservice体系结构过于复杂。
Joop Eggen 2014年

当允许数据库读取时,数据库的每个细节都将成为公共API的一部分。我不想在如此复杂的API上保持兼容性。
Patrick

但是在那种情况下,至少不是出于语义目的,视图不就成为了API的一部分吗?只是您要调用什么API以及迫使您进行维护的问题。(通常,数据库上方的一层更易于保持一致。)
lc。

我同意,该视图将只是API的一种形式。我认为大多数回答这个问题的人都没有读过我关于将视图用作抽象级别的想法。我了解,尽管如果改变数据库技术来保持视图完整将是一项重大挑战,但是我敢打赌,在接下来的5年中我们将不需要改变数据库技术。而且,只有5家工厂的用户就不会有性能问题。因此,考虑到我们的规模,尽管这里的答案似乎表明我正直奔痛苦的世界,但我还是感谢我会寻求这种解决方案。
大卫

Answers:


68

数据库不太擅长信息隐藏,这很合理,因为数据库的工作是实际公开信息。但这使它们成为封装时的糟糕工具。为什么要封装?

场景:您将几个组件直接绑定到RDBMS,并且看到一个特定的组件成为性能瓶颈,您可能想对其取消规范化数据库,但是您不能这样做,因为所有其他组件都会受到影响。您甚至可能意识到与RDBMS相比,使用文档存储或图形数据库会更好。如果数据是由小型API封装的,则您将有实际机会以所需的任何方式重新实现所述API。您可以透明地插入缓存层,而不能插入。

直接从应用程序层对存储层进行摸索,与依赖关系反转原理建议的做法截然相反。


1
这是一个好点!让我不那么担心的一件事是,Postgres现在已经支持文档存储和RDBMS(withouttheloop.com/articles/2014-09-30-postgresql-nosql)。不过,您的观点仍然有效,我会仔细考虑。
大卫

3
它不应该让您担心@David仅仅因为工具可以完成某事并不意味着更改它不会破坏很多事情。这就是一定程度的分离点-您可以完全更改API背后的数据,而无需更改用户看到的内容。我在这里以数据库管理员的身份发言……只要客户端看到的内容相同,就可以根据需要任意更改后端。
2014年

1
@David虽然这是一个有趣的消息,但与我描述的场景无关。如果将数据库模式从关系模式更改为基于文档的数据库模式,它将对所有依赖它的数据库模式产生相同的影响:您将不得不重写所有查询。还有一次噩梦,必须立即部署所有这些更改,以便在整个系统中维护组件之间的兼容性。
back2dos 2014年

1
@David:限制对一些定义明确的视图的访问可以说是建立另一个API的好处。只要只是视图,就只能使用只读访问权限。并且拥有一个组件同时依赖于服务API和视图API使得它非常脆弱。因此,如果要使组件依赖于视图,则已将其预定为只读或高维护性。我在这里闻到技术债务。另外,您可能想以数据库不允许的方式添加水平分区。
back2dos 2014年

2
@David:从长远来看,更改代码要比编写代码容易得多,这更重要。架构没有说“您不应该以这种方式编写代码”,而是说“如果这样做,您将遭受试图维护它的可怕噩梦”。如果您正在谈论原型,则不需要维护。前进。原型应尽可能容易地证明这一点。但是,当尝试将所有已证明的要点整合到系统中而又不会演变为西西弗斯人自生的酷刑时,最好再加倍努力。
back2dos 2014年

54

微服务更重要和重要的是:API或数据库架构?API,因为那是它与世界其他地方的合同。数据库模式只是存储服务管理的数据的一种简便方法,希望以优化微服务性能的方式进行组织。开发团队应该可以随时自由地重组该架构-或切换到完全不同的数据存储解决方案。世界其他地方应该不在乎。当API更改时,世界其他地方都在乎,因为API是合同。

现在,如果您浏览他们的数据库

  • 您在其架构上添加了不必要的依赖关系。他们无法更改它,而不会影响您的服务。
  • 您向其内部添加了不必要且不可预测的负载。
  • 您自己的服务的性能将受到其数据库性能的影响(他们将尝试优化其服务以使客户端性能良好,而其数据库仅针对其服务性能良好)
  • 您将实现与可能无法准确,有区别地表示其数据存储中资源的模式相关联-它可能具有额外的细节,这些细节仅用于跟踪内部状态或满足其特定实现(您不必在意)。
  • 您可能无意间破坏或破坏了他们的服务状态(他们不会知道您正在这样做)
  • 您可以在他们不知道发生这种情况的情况下,从他们的数据库中更新/删除/删除资源。

如果仅授予您读取访问权限,则最后两点可能不会发生,但是其他两点已经足够了。共享数据库是一件坏事。

对于经验不足的开发人员(或不学习的人),通常认为数据库比服务更重要,将数据库视为真实事物,而将服务视为获得服务的一种方式。那是错误的方法。


4
请注意,即使您是唯一负责整个项目的开发人员,上述所有要点均有效。即使是一个人管理一个复杂的项目,也会引起所有这些担忧。
itsbruce 2014年

15

微服务架构很难描述,但是思考它的最好方法是面向组件的架构与面向服务的架构之间的结合。作为一套软件,软件由许多小型业务组件组成,这些业务组件负责非常具体的业务领域。在提供的服务或必需的服务中,它们通过明确定义的服务的API与外界的接口。

写入甚至读取组件业务领域之外的数据库都违反了这种体系结构。

这样做的主要原因是,由另一个软件组件通过服务提供的API具有合理的期望,即随着服务提供组件的新版本可用,该API最有可能向后兼容。如果我是“提供”组件的开发人员,则只需担心与API的向后兼容性。如果我知道还有其他三个开发团队直接针对我的数据库编写自定义查询,那么我的工作就会变得更加复杂。

更糟糕的是,也许其他编写这些内容的团队在关键项目中处于中等水平,他们现在不能接受您组件中的更改。现在,您所拥有的业务域上的组件的软件开发正由另一个业务域上的开发驱动。

通过服务进行的完全交互会减少各种软件组件之间的耦合,因此不会经常发生这种情况。当使用数据库中的视图涉及其他组件时,如果其他人对此视图进行了查询,则您将具有使视图向后兼容的更多功能。但是,我仍然觉得这应该是例外情况,并且仅应用于可能需要应用程序读取大量数据的报告或批处理过程。

显然,这在大型分布式团队中很有效,在大型分布式团队中,开发团队被业务领域(如Amazon)隔开。如果您是一家小型开发商店,那么您仍然可以从这种模型中受益,特别是如果您需要快速启动大型项目,而且还必须处理供应商软件时。


4

在过去的20年中,我已经看到了一些大型的模块化数据库设计,并且我已经看到David提出的方案很多次了,其中应用程序对自己的模式/表集具有写访问权,而对另一个模式/表具有读访问权。组表。应用程序/模块获得只读访问权限的数据通常可以描述为“主数据”

在那个时候,我还没有看到以前的答案所暗示的问题,所以我认为值得更详细地了解前面的答案中提出的观点。

场景:您将几个组件直接绑定到RDBMS,并且看到一个特定的组件成为性能瓶颈

我同意此评论,只是这也是一个论点,即在本地具有数据副本以供微服务读取。也就是说,大多数成熟的数据库都支持复制,因此,如果需要或需要的话,无需任何开发人员的努力,就可以将“主数据”物理复制到微服务数据库中。

有些人可能会以较旧的名义将其识别为“企业数据库”,将核心表复制到“部门数据库”。这里的要点是,通常,如果数据库通过内置的更改数据复制(仅增量形式,以二进制形式且对源数据库的成本最低)为我们做到这一点,那将是很好的。

相反,如果我们的数据库选择不允许这种“现成的”复制支持,那么我们可能会遇到想要将“主数据”推送到微服务数据库的情况,这可能会导致开发人员花费大量精力,并且效率也大大降低。

可能想对数据库进行非规范化,但是您不能这样做,因为所有其他组件都会受到影响

对我来说,这种说法是不正确的。非规范化是“加性”更改,而不是“重大更改”,并且任何应用程序都不应由于非规范化而中断。

破坏应用程序的唯一方法是应用程序代码使用“ select * ...”之类的东西,并且不处理多余的列。对我来说,那是应用程序中的错误?

非规范化如何破坏应用程序?对我来说听起来像是FUD。

模式依赖:

是的,应用程序现在依赖于数据库架构,这意味着这应该是一个主要问题。虽然添加任何额外的依赖关系显然不是理想的,但我的经验是对数据库架构的依赖关系不是问题,那么为什么会这样呢?我只是幸运吗?

主要的数据

我们通常可能希望微服务具有只读访问权限的模式是我通常所说的企业“ 主数据 ”。它具有企业必需的核心数据。

从历史上看,这意味着我们添加依赖关系的架构既成熟又稳定(对企业而言是基本的且不变)。

正常化

如果有3位数据库设计师去设计标准化的db模式,那么他们将最终采用相同的设计。好的,可能会有一些4NF / 5NF变化,但变化不大。此外,设计人员还可以提出一系列问题来验证模型,以便设计人员可以确信他们已经达到了4NF(我是否过于乐观?人们是否正在努力达到4NF?)。

更新:通过4NF这里我指的模式中的所有表了自己的最高标准形式提供多达4 NF(所有表得到了适当的标准化高达4NF)。

我认为规范化设计过程就是为什么数据库设计人员通常对依赖规范化数据库架构的想法感到满意的原因。

规范化的过程使数据库设计进入了已知的“正确”设计,并且从那里进行的变体应针对性能进行非规范化。

  1. 支持的数据库类型可能有所不同(JSON,ARRAY,地理类型支持等)
  2. 有人可能会主张基于4NF / 5NF的变化
  3. 我们排除物理差异(因为这无关紧要)
  4. 我们将其限制为OLTP设计而不是DW设计,因为这些是我们要授予对以下内容的只读访问权限的模式

如果给3位程序员提供了一个设计方案来实现(作为代码),那么期望将是3种不同的实现方式(可能非常不同)。

对我来说,可能存在一个“信仰归一化”的问题。

破坏模式的改变?

非规范化,添加列,更改列以增加存储量,使用新表扩展设计等都是不间断的更改,并且达到第四范式的数据库设计人员将对此充满信心。

显然,可以通过删除列/表或进行中断类型更改来进行中断更改。可能是的,但实际上,我在这里完全没有遇到任何问题。也许是因为了解什么是重大变更,并且这些变更得到了妥善管理?

我很想听听在共享只读模式的上下文中破坏模式更改的情况。

微服务更重要和重要的是:API或数据库架构?API,因为那是它与世界其他地方的合同。

虽然我同意这一说法,但我认为我们可能会从企业架构师那里听到一个重要的警告,那就是“数据永远存在”。也就是说,尽管API可能是最重要的,但数据对于整个企业也非常重要,而且很长一段时间都非常重要。

例如,一旦需要填充用于商业智能数据仓库,则从业务报告的角度来看,无论API如何,模式和CDC支持都变得很重要。

API有问题吗?

现在,如果API既简单又完美,那么所有问题都将成为现实,因为我们总是选择一个API,而不是拥有本地只读访问权限。因此,甚至考虑本地只读访问的动机是,使用本地访问可以避免的API可能会出现一些问题。

What motivates people to desire local read-only access?

API优化:

LinkedIn有一个有趣的演讲(从2009年开始),涉及优化API的问题以及为什么它对他们的规模如此重要。http://www.slideshare.net/linkedin/building-consistent-restful-apis-in-a-highperformance-environment

简而言之,一旦API必须支持许多不同的用例,就很容易陷入这种情况:从网络角度和数据库角度来看,它最佳地支持一个用例,而其他情况则差劲。

如果API与LinkedIn的复杂程度不同,那么您可以轻松获得以下场景:

  • API获取的数据远远超出您的需要(浪费)
  • Chatty API,您必须多次调用该API

是的,我们当然可以为API添加缓存,但是最终API调用是远程调用,当数据是本地数据时,开发人员可以进行一系列优化。

我怀疑那里有人可能将其加起来为:

  • 将主数据低成本复制到微服务数据库(无开发成本且技术高效)
  • 对规范化的信念以及应用程序对架构更改的适应力
  • 能够轻松优化每个用例并潜在地避免闲聊/浪费/低效的远程API调用
  • 加上约束和连贯设计方面的其他一些好处

这个答案太长了。道歉!!


添加列通常会中断应用程序。如果您具有“工资”,则在引入新列“ salary_currency”时,汇总所有工资的应用程序将中断。
kubanczyk

真?我想取决于您对“休息”的定义。如果该应用程序在生产中且按预期运行且没有“ salary_currency”,为什么您会认为该应用程序现在已损坏?
Rob Bygrave

应用程序运行无错误,并显示一些数字。但这没用。当CEO看到上个月的工资总额是600万,而不是5万(因为一名新雇员以韩元获得工资)时,关于有用/无用产出的定义将不多讨论。
kubanczyk

0

状态管理(可能是数据库)可以部署在微服务的容器中,并通过API公开。微服务的数据库对容器外部的其他系统(仅API)不可见。或者,您可以让另一个服务(例如缓存)通过API管理状态。将所有微服务的依赖关系(除了对其他服务的API调用之外)包含在单个可部署容器中是体系结构中的关键区别。如果没有得到,请回去研究架构。

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.