自治微服务,事件队列和服务发现


15

最近,我一直在阅读有关微服务的很多文章,这是到目前为止我得出的一些结论(如果我在任何时候错了,请更正我)。

  1. 微服务架构与域驱动设计配合得很好。通常一个MS代表一个有界上下文。
  2. 如果微服务A需要驻留在微服务B中的功能,则我的模型可能是错误的,并且AB 实际上应该是一个微服务/ BC。
  3. 微服务之间的同步通信(直接HTTP请求)很糟糕,导致它违背了微服务的目的,并引入了组件之间的耦合。
  4. 服务之间的异步通信是可取的。服务应将事件发布到消息队列,以便其他服务可以订阅和处理事件的一部分,或使用它复制上下文所需的部分数据。这样,服务可以处理请求,甚至其他服务也已关闭,而在同步通信中则不会。
  5. 如果微服务A发布事件,微服务B订阅该事件并产生一个新事件作为结果,则微服务A不应是一个正在处理的新创建事件,因为这将是循环依赖性。在这种情况下,我们应该引入第三种微服务,或者将AB合并到AB微服务中。
  6. 微服务实际上是一个误导性术语。我们应该为小环境而努力,但这不是必须的。术语不应该是“微服务”,而是“ 足够大以进行工作服务 ”。
  7. 微服务使我们可以更轻松地引入新功能,而不必担心会破坏整个系统。可以通过引入新服务或重构现有服务之一来完成。
  8. 每个微服务都应具有自己的数据存储。数据复制/复制是此体系结构中的理想行为。

除了证实我对这种体系结构的理解之外,问题的其他部分主要与服务发现有关。如果服务异步通信,并使用亚马逊SQS之类的中央事件队列,这是否意味着服务发现在这样的体系结构中没有位置?

服务不应对系统中的其他服务有任何了解。他们只知道应该发布或订阅的上下文和事件吗?

Answers:


4

您的结论似乎主要是根据,并很好地总结了微服务的发展方向。

但是,我不会完全支持2、5和8:

  • 2)简单的依存关系不应自动导致合并。您必须考虑此类相关呼叫的频率以及其他服务的呼叫频率。

    因此,如果微服务A非常频繁地需要微服务B中的功能,而其他微服务很少需要微服务B,则应挑战设想的结构,并询问将这两个微服务组合在一起是否更合适。

  • 5)当然,您需要避免消息处理中无休止的循环。

    但是添加中介并不能阻止它:A可以启动C处理的消息,而C启动B处理的消息,B启动A处理的消息,从而使您陷入循环。

    无法仅通过考虑微服务级别来评估该问题:问题实际上是有关消息类型和内容的信息,这可能会导致循环。因此,必须对整个服务中的消息分发和处理进行建模的图形进行整体分析(实际上这可能很复杂,因此您可以想象一个监视微服务可以检测到这样的周期并破坏它们)。

  • 8)是,每个微服务都应具有其专用的存储/数据库。

    为了使服务独立,需要最少的复制。但是,我不会说得很清楚是否需要复制:必须将复制保持在最低限度,以避免通过复制过程进行隐藏耦合。

    微服务是关于松散耦合的。有时可以通过调用另一个微服务来检索相关数据而不是复制数据来更有效地实现。

最后两个没有编号的申明过于宽泛,以至于无法在这里坚定地回答。我认为您的建议是一个很好的起点,但这确实取决于体系结构要求和约束。


“通过调用另一个微服务来检索相关数据而不是复制数据,有时可能会更有效地实现这一点。”因此,一点点同步通信和直接调用(通过HTTP)以获取数据的某些部分并没有什么问题,例如只要该查询不代表分布式事务/命令,否则我们不能保证该命令的原子性吗?
罗伯特

1
这里没有完美的解决方案:它是松耦合和封装(microservices.io/patterns/data/database-per-service.html)反对easyness但冗余(平衡microservices.io/patterns/data/event-driven-architecture .html)(总体情况下)(microservices.io/patterns/microservices.html
Christophe

3

微服务与解耦不同的功能域有关。可以由不同的团队使用不同的技术堆栈以不同的速度开发每种服务。这创造了组织上的灵活性。需要权衡的是操作复杂性,其中每项额外的服务都会创建另外一项必须在操作环境中进行管理的事物。因此,整体与微服务的基本权衡不是要避免依赖关系,而是要避免锁定步骤的开发和部署,因为这些步骤必须同时装运所有东西,但要付出更多的代价,因为存在更多的运动部件。

服务不应对系统中的其他服务有任何了解。他们只知道应该发布或订阅的上下文和事件吗?

避免依赖的问题是一个红鲱鱼。您将始终在产品的各个部分之间具有依赖关系,并且无论它们是在单独的服务中还是在同一代码的一部分中,都不会改变依赖关系可能中断的事实。它们可能会在操作级别上中断,因为关键服务器已关闭,您可以通过操作冗余和故障转移实践来进行管理。它们也可能在集成级别中断,因为零件以不兼容的方式更改,您可以通过集成测试来检测它们。服务之间的改组代码不能解决潜在的依赖破坏问题。避免破坏依赖关系的解决方案是操作冗余和集成测试,这与您的服务规模无关。

如果服务正在异步通信,并使用诸如Amazon SQS之类的中央事件队列,这是否意味着服务发现在这样的体系结构中没有位置?

要回答该问题,请首先回答以下问题:为什么要异步通信?是否简化了独立组件的独立开发?是否可以提高24/7系统的操作可用性?假设是后者,您希望使用队列将数据复制到本地数据库。好吧,现在您的数据可以过时了。在某些时候它会过时。您如何应对?此外,如何确保队列的运行可用性,队列是另一个运行时组件?您如何确保这些本地数据库的可用性?现在,您可以管理多个数据库集群,而不是管理一个数据库集群。您的运营团队可以处理此工作量吗?确实,当您构建一个简单的整体组件时,也许您的用户会更高兴拥有更多功能并且每个月有几小时的停机时间,这种复杂性值得吗?

我想你明白我的意思。系统设计不是关于对与错,而是要从各种各样的权衡中进行选择。如果您只在正确的上下文中看到错误,则所有错误的内容都可能是正确的,反之亦然。你的环境是独一无二的你,因此,虽然我们可以给你一个答案,它不会答案。记住您的听众是谁,他们的需求是什么,正确的设计就会显示出来。


2
  1. 微服务架构与域驱动设计配合得很好。通常一个MS代表一个有界上下文。

不同意。DDD往往非常面向对象。订单已交付?Order.Deliver(),而微服务将具有DeliveryService.Deliver(order)

  1. 如果微服务A需要驻留在微服务B中的功能,则我的模型可能是错误的,并且A和B实际上应该是一个微服务/ BC。

不同意,您应该尝试使微服务保持微状态。将它们分割得更小!

  1. 微服务之间的同步通信(直接HTTP请求)很糟糕,导致它违背了微服务的目的,并引入了组件之间的耦合。

不同意。服务不应该在乎谁在调用它们,调用者也不应该在乎逻辑是在微服务中实现的。

  1. 服务之间的异步通信是可取的。服务应将事件发布到消息队列,以便其他服务可以订阅和处理事件的一部分,或使用它复制上下文所需的部分数据。这样,服务可以处理请求,甚至其他服务也已关闭,而在同步通信中则不会。

队列很好。但是你的推理是错误的。同步响应和异步之间的唯一区别是您等待同步。您可以使用队列和多个工作程序(无问题)来实现RPC样式调用。

  1. 如果微服务A发布事件,微服务B订阅该事件并产生一个新事件作为结果,则微服务A不应是一个正在处理的新创建事件,因为这将是循环依赖性。在这种情况下,我们应该引入第三种微服务,或者将A和B合并到AB微服务中。

不同意。它不是循环依赖项,因为您的微服务未耦合。另外,您还想满足重新发送邮件的需求,SendEmail,EmailFailed,SendAgain不需要3个微服务

  1. 微服务实际上是一个误导性术语。我们应该为小环境而努力,但这不是必须的。术语不应该是“微服务”,而是“足够大以进行工作服务”。

不同意。查看纳米服务。

  1. 微服务使我们可以更轻松地引入新功能,而不必担心会破坏整个系统。可以通过引入新服务或重构现有服务之一来完成。

不同意。是的,您会脱钩,但是微服务的编排可能像任何整体项目一样令人生畏

  1. 每个微服务都应具有自己的数据存储。数据复制/复制是此体系结构中的理想行为。

不同意。尽管您不应该共享存储,但是您的微服务应该尽可能地做到无状态。除非进行中,否则不要复制数据


1

您的结论是很好的经验法则,但并不通用。在某些情况下,即使在新建项目中,最好的选择就是打破这些规则。在某些情况下,同步通信是最佳选择。在某些情况下,即使通过同步通信将两个服务合并为一个服务,也不是一件好事。

另一个问题是,基于队列的通信不需要服务发现。


0

嗯,您只是在谈论面向对象的编程。至少,或者最初的想法是:使用消息相互通信的独立运行代码段。

艾伦·凯(Alan Kay)认为OOP是仿照生物系统建模的,其中的细胞彼此相对独立,并且仅通过插入其他细胞外部接口的消息进行通信。

那么,为什么仅仅因为所有对象都不在同一台计算机上运行而停止将其视为OOP吗?如果有的话,那将比它们在同一台计算机上并且在同一应用程序的一部分中更面向对象,因为如果所有对象都在同一应用程序中,那么开发人员通常会使用所有类和所有对象共享的全局变量来破坏OOP。包括每个文件中的相同标头,等等。当所有对象都依赖于同一个东西时,它们的封装就不会像它们彼此完全独立一样,并且封装是OOP的重点。

例如,其他答案中所说的几乎所有内容都是关于OOP的教科书声明。


0

由于我经常遇到对诸如“绑定上下文”和“核心域”之类的重要概念的错误理解,因此我想对此进行详细说明。

我发现将子域视为业务能力极其有利可图。业务能力是您的组织所要做的。它是其业务功能之一。由于我们的目标是业务与IT保持一致,所以我绝对希望他们与我的技术服务保持1:1关系

因此,此过程可归纳为以下内容。首先,我定义更高级别的业务功能。它应采用名词和动词的形式(或某些派生形式)。通常,业务能力不到10个。然后,我将更深入地了解嵌套功能。依此类推,直到没有任何分裂。您使用这种方法获得的功能反映了组织的真实领域和真实工作方式。这些功能在本质上是松散耦合的,因此,如果将技术服务映射到该功能,它们将是自主的并且是事件驱动的。这个过程称为业务能力映射,但是还有其他找到服务的方法,其中最突出的可能是价值链分析

这是使用此方法识别服务边界的示例

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.