微服务和数据库连接查询

143
针对将单块应用程序分解为微服务的人们,您如何处理破解数据库的难题。我所涉及的典型应用程序出于性能和简单性的原因,进行了大量的数据库集成。
如果您有两个在逻辑上不同的表(如果您愿意,可以称之为有界上下文),但通常对大量数据进行聚合处理,则在单块中,您很可能会避免使用面向对象编程,而是使用数据库的标准JOIN功能,在返回聚合视图之前在数据库上处理数据。
那么,当您需要将这些数据拆分为微服务时,如何证明其有效性?毕竟,您可能需要通过 API 联接数据,而不是通过数据库。
我已经阅读了 Sam Newman 的《微服务》一书,在“拆分单块”一章中,他给出了一个“破解外键关系”的例子,并承认通过 API 进行联接会更慢 - 但他接着说,如果您的应用程序已经足够快了,那它变慢了又有何妨呢?
这似乎有些肤浅? 您有哪些经验? 您使用了什么技术使 API 联接表现良好?

4
好问题,我也遇到了同样的问题,最终我创建了一个物化视图,并在其上执行了连接操作。我不太喜欢这种做法,但我想这可能是使用微服务时要面临的挑战。这并没有确定的正确做法,只是一种设计选择。我知道很多人会建议使用物化视图,但聚合响应会成为一个问题。如果你找到更好的解决方案,请让我知道。 - PavanSandeep
我知道这是旧的了,但是GraphQL能解决这个问题吗?我还在研究如何进行分段迁移,并且似乎GraphQL是使之无缝进行的方法。 - themightybun
在某个时候,你应该意识到教条主义并不是正确的方法。GraphQL 是在数据源之外进行聚合的一个不错的例子,通常它能够正常工作。 - Christian Ivicevic
5个回答

33
  • 当性能或延迟不太重要时(是的,我们并不总是需要它们),只需使用简单的RESTful API查询所需的附加数据即可。如果您需要调用多个不同的微服务并返回一个结果,则可以使用API网关模式。

  • Polyglot persistence环境中具有冗余是完全可以的。例如,您可以为微服务使用消息队列,并在每次更改内容时发送“更新”事件。其他微服务将监听所需的事件并在本地保存数据。因此,您可以将所有必需的数据保留在特定微服务的适当存储中,而无需查询。

  • 此外,不要忘记缓存 :) 您可以使用像RedisMemcached这样的工具,以避免过于频繁地查询其他数据库。


30
所有的建议都不错,但我仍然觉得难以理解。也许是因为我们习惯了在数据库中进行大量的处理。我们当前的应用程序有复杂的存储过程,可以处理大量数据,然后返回一个小的结果集。在微服务架构中,我认为这些实体应该被拆分成不同的有界上下文。我们知道当前的方法很糟糕,但很难证明将所有数据带回应用层进行处理的价值。也许更多的去规范化或预计算聚合视图会有所帮助。 - Martin Bayly
1
是的,我明白了。微服务方法并不适用于每个人,您应该谨慎地应用它。也许您可以从较小的更改开始。 - sap1ens
可能程序员StackExchange是一个更好的地方来问这个问题: http://programmers.stackexchange.com/questions/279409/how-does-polyglot-persistence-handle-relational-data 以及其他标记为微服务的问题 http://programmers.stackexchange.com/questions/tagged/microservices - Martin Bayly

15

在服务中拥有只读的复制参考数据来自其他服务是可以的。

在将单体数据库重构为微服务时(而不是重写),我会:

  • 为该服务创建一个数据库模式
  • 在该模式中创建版本化的视图,用于将数据从该模式公开给其他服务
  • 针对这些只读视图执行联接操作

这将使您能够独立地修改表数据/结构,而不会破坏其他应用程序。

与使用视图不同,我可能还会考虑使用触发器来将数据从一个模式复制到另一个模式。

这将是向正确方向进行的增量进展,建立组件的接缝,并且可以稍后转移到REST。

* 视图可以扩展。如果需要破坏性更改,请创建同一视图的v2版本,并在不再需要旧版本时删除它。 ** 或表值函数,或存储过程。


9

CQRS---命令查询聚合模式是Chris Richardson的答案。 让每个微服务更新自己的数据模型并生成事件,这些事件将更新具有先前微服务所需联接数据的物化视图。这个MV可以是任何查询优化的NoSql DB或Redis或elasticsearch。这种技术导致了最终一致性,这绝对不是坏事,并避免了实时应用程序端的联接。 希望这回答了您的问题。


5
我会将解决方案分为使用领域,比如操作和报告。
对于微服务的操作情况,它们提供单个表单所需的数据,需要从其他微服务获取数据(这是操作情况),我认为使用API连接是可行的。您不会处理大量数据,可以在服务中进行数据集成。
另一种情况是当您需要在大量数据上执行大查询以执行聚合等操作时(即报告用例)。对于这种情况,我建议维护一个共享数据库 - 类似于原始方案,并使用来自微服务数据库的事件更新它。在此共享数据库上,您可以继续使用存储过程,这将节省您的工作量并支持数据库优化。

3
在微服务中,您需要创建不同的读模型。例如:如果您有两个不同的边界上下文,并且有人想要在这两个数据上进行搜索,则需要有人从两个边界上下文中侦听事件并为应用程序创建特定视图。
在这种情况下,需要更多的空间,但不需要连接和联接。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接