数据二分法:重新考虑与数据和服务的关系

大家好!我们有一个好消息,6月,OTUS将再次开设“软件架构师”课程,与之相关的我们传统上会与您分享有用的材料。




如果您在没有任何上下文的情况下使用微服务来了解整个故事,那么您可以认为它有些奇怪。将应用程序划分为通过网络连接的片段,当然意味着向最终的分布式系统添加复杂的容错模式。

尽管该方法包括拆分成许多独立的服务,但最终目标远不只是这些服务在不同机器上的操作。我们正在谈论与外界的互动,从本质上讲,它也是分布式的。不是从技术意义上,而是从由许多人,团队,程序组成的生态系统的意义上,而每个部分都必须以某种方式完成其工作。

例如,公司是一组分布式系统,它们共同为实现某个目标做出了贡献。几十年来,我们一直忽略这一事实,试图实现统一,通过FTP或使用公司集成工具传输文件,同时专注于我们个人隔离的目标。但是随着服务的出现,一切都发生了变化。服务帮助我们超越了视野,看到了相互协作的程序的世界。但是,为了成功工作,有必要实现和设计两个根本不同的世界:我们生活在许多其他服务生态系统中的外部世界,以及我们独自统治的个人内心世界。



这种分散的世界不同于我们成长和习惯的世界。构建传统的整体架构的原则不能遭到批评。因此,对此类系统的正确理解不仅仅是在白色标记板上创建教室图或很酷的概念证明。关于这样的系统能够长期有效地工作。幸运的是,服务已经出现了很长一段时间,尽管它们看起来确实有所不同。SOA课程仍然具有相关性,甚至可以使用Docker,Kubernetes和稍微有些破旧的时髦胡须来调味。

因此,今天,我们探讨了规则的变化方式,为什么我们需要重新考虑彼此之间传输的服务和数据的方法,以及为什么需要完全不同的工具。

封装不会永远是您的朋友


微服务可以彼此独立地工作。正是这种属性为他们带来了最大的价值。相同的属性允许服务扩展和增长。从缩减到四千万用户或PB级数据(尽管在这里他们可以提供帮助)而言,与其说是多少,不如从人员的角度来看,因为团队和组织在不断发展。



但是,独立是一把双刃剑。也就是说,服务本身可以轻松自然地旋转。但是,如果在服务内部实现了需要使用其他服务的功能,那么最后我们必须几乎同时对两个服务进行更改。在整体中,这很容易做到,您只需进行更改并将其发送到发行版,但是在独立服务同步的情况下,将会出现更多问题。团队和发布周期之间的协调破坏了灵活性。



作为标准方法的一部分,只需避免烦人的端到端更改,即可在服务之间明确划分功能。这里的单点登录服务就是一个很好的例子。他具有明确定义的角色,使他有别于其他服务。如此明确的分离意味着在围绕其服务的需求快速变化的世界中,单点登录服务不太可能改变。它存在于严格受限的环境中。



问题在于,在现实世界中,业务服务无法不断保持角色的平等分离。例如,相同的业务服务与来自其他类似服务的数据一起工作更多。如果您从事在线零售,那么处理订单流,产品目录或用户信息将成为许多服务的要求。每个服务都需要访问此数据才能工作。


大多数业务服务使用相同的数据流,因此它们的工作总是交织在一起的。

因此,我们得出了一个值得讨论的重要观点。尽管服务对于在很大程度上分开工作的基础结构组件而言运作良好,但是大多数业务服务却更加相互交织。

数据二分法


面向服务的方法可能已经存在,但是关于如何在服务之间交换大量数据的信息仍然很少。

主要问题是数据和服务是不可分割的。一方面,封装鼓励我们隐藏数据,以便服务可以彼此分离,并促进服务的增长和进一步的变化。另一方面,我们需要能够自由共享和统治一般数据以及任何其他数据。它意味着能够像在任何其他信息系统中一样自由地立即开始工作。

但是,信息系统与封装无关。实际上,甚至相反。数据库会尽其所能来访问存储在其中的数据。它们带有强大的声明性界面,可让您根据需要修改数据。此类功能在初步研究阶段很重要,但对于管理不断发展的服务日益增长的复杂性并不重要。



这就产生了一个难题。矛盾。二分法。毕竟,信息系统与提供数据有关,而服务与隐藏有关。

这两种力量是根本。它们构成了我们大部分工作的基础,并不断努力在我们创建的系统中追求卓越。

随着服务系统的发展和发展,我们看到了数据二分法的不同表现形式。服务接口将会增长,提供越来越广泛的功能,并开始看起来像一个非常棒的本地数据库,或者我们将感到失望,我们将实现某种方法来从服务到服务提取或移动大量数据集。



反过来,创建看起来像一个很棒的本地数据库的东西会导致许多问题。我们不会详细讨论共享数据库有何危险,只是说它对试图使用共享数据库的公司而言是巨大的工程和运营难题

更糟糕的是,数据量使服务边界问题倍增。服务内部的数据越常见,接口将变得越困难,并且合并来自不同服务的数据集也将越困难。

提取和移动整个数据集的另一种方法也有其问题。解决此问题的常用方法是简单地检索和存储整个数据集,然后将其本地存储在每个消费者服务中。



问题在于,不同的服务对它们消耗的数据的解释不同。这些数据随时可用。它们在本地进行修改和处理。很快他们就与源数据不再有任何共同之处。


副本越易变,数据随时间变化的越多。

更糟糕的是,这样的数据很难回溯(MDM确实可以在这里解决)。实际上,企业所面临的一些棘手的技术问题是由于异构数据在应用程序之间的繁衍所致。

要找到有关共享数据的此问题的解决方案,您需要采取不同的思路。它们应该成为我们构建的体系结构中的一流对象。帕特·海兰称此类数据为“外部”,这是非常重要的功能。我们需要封装,以免暴露服务的内部结构,但是我们必须促进服务对共享数据的访问,以便它们可以正确执行其工作。



问题在于,今天没有一种方法适用,因为服务接口,消息传递或共享数据库都没有提供处理外部数据的良好解决方案。服务接口不适合任何规模的数据交换。消息传递会移动数据,但不会存储其历史记录,因此数据会随着时间的推移而损坏。共享数据库过于关注某一点,这阻碍了进度。我们不可避免地陷入了数据故障周期:


数据破产周期

流:数据和服务的去中心化方法


理想情况下,我们需要改变服务如何处理共享数据的方法。目前,任何方法都面临着上述的二分法,因为没有神奇的花粉可以大量撒在上面,并使其消失。但是,我们可以重新考虑问题并做出妥协。

这种妥协涉及一定程度的集中化。我们可以使用分布式日志机制,因为它提供了可靠的可伸缩流。现在,我们需要能够加入这些通用线程并与它们一起工作的服务,但是我们想要避免执行此处理的复杂的集中式上帝服务。因此,最好的选择是将流处理嵌入到每个消费者服务中。因此,服务将能够组合来自不同来源的数据集,并根据需要使用它们。

实现此方法的一种方法是使用流平台。有很多选择,但是今天我们将考虑Kafka,因为使用其有状态流处理可以使我们有效地解决所提出的问题。



使用分布式日志记录机制使我们可以遵循一条通俗易懂的路径,并使用消息传递来处理面向事件的体系结构。据信,这种方法比请求-响应机制提供了更好的缩放和分离,因为它可以控制流向接收者而不是发送者。但是,您必须为此付出一切,在这里,您需要经纪人。但是对于大型系统而言,这种权衡是值得的(这对于您的普通Web应用程序而言还不可以说)。

如果代理负责分布式日志记录,而不是传统的消息传递系统,则可以利用其他功能。传输几乎可以像分布式文件系统一样线性扩展。数据可以长时间保存在日志中,因此我们不仅获得消息传递,还获得信息存储。可扩展存储,无需担心可变状态。

然后,您可以使用有状态流处理机制将声明性数据库工具添加到使用者服务。这是非常重要的一点。尽管数据存储在所有服务都可以访问的共享流中,但是服务进行的池化和处理是私有的。他们发现自己受到严格限制的孤立。


通过划分状态的免疫流来摆脱数据二分法。然后使用状态流处理将此功能添加到每个服务。

因此,如果您的服务必须与订单,产品目录和仓库一起使用,它将具有完全访问权限:只有您才能决定要合并的数据,在何处处理以及随着时间的变化应如何更改。尽管数据是通用的,但与它们的工作已完全分散。它是在每个服务中创建的,在这个世界中一切都按照您的规则进行。


共享数据,以免破坏其完整性。在需要它的每个服务中封装一个函数,而不是源。

碰巧的是,数据需要大量移动。有时,服务需要所选数据库引擎中的本地历史数据集。诀窍在于,您可以保证在必要时可以通过访问分布式日志记录机制从源还原副本。卡夫卡的连接器在这方面做得很好。

因此,今天考虑的方法具有几个优点:

  • 数据以共享流的形式使用,可以在日志中长时间存储,并且在每个单独的上下文中都连接了用于处理共享数据的机制,这使服务可以快速,轻松地工作。这样,您可以平衡数据的二分法。
  • , , . .
  • Stateful Stream Processing , , .
  • , , , -.
  • , . , .
  • , .

如您所见,这不仅仅是REST。我们提供了一套工具,可让您以分散的方式处理共享数据。

在今天的文章中,并未公开所有方面。我们仍然需要决定如何在请求-响应范式和面向事件的范式之间取得平衡。但是我们下次会处理。您需要了解一些主题,例如,为什么有状态流处理如此出色。我们将在第三篇文章中讨论这一点。如果需要的话,还有其他强大的设计可以使用,例如Exactly Once Processing。借助它的帮助,更改了分布式业务系统的游戏规则,因为该设计为XA提供了交易保证。以可扩展形式。这将在第四篇文章中讨论。最后,我们将需要仔细研究这些原则的实施细节。



但是现在,请记住以下几点:数据二分法是我们在创建业务服务时面临的力量。我们必须记住这一点。诀窍是将所有内容颠倒过来,并开始将常规数据视为一流的对象。有状态流处理为此提供了一个独特的折衷方案。他避免了集中化的“上帝组成部分”阻碍进度。此外,它还提供了数据流管道的速度,可伸缩性和容错能力,并将其添加到每个服务中。因此,我们可以专注于意识的一般流,任何服务都可以连接到该意识流并使用其数据。因此,服务更具可伸缩性,可互换性和自治性。因此,它们不仅在白板上以及在检验假设时看起来不错,而且还要工作和发展数十年。



.



All Articles