在第一章中,我们介绍并总结了数据网格架构的四个支柱。现在,我们将将这些入门知识应用于流式数据网格。简而言之,流式数据网格是一个满足所有支柱要求的数据网格,以流式数据的形式实现。换句话说,在数据从源头摄取后,数据在到达消费领域之前没有任何时刻停留在数据存储中。数据产品保留在流中,直到其保留期结束。
将数据产品保留在流中需要使用到数据网格的所有自助服务工具和服务。考虑一个简单的ETL过程。从源头提取数据的组件需要将数据放入流中。接下来,对数据进行转换的引擎需要在流中进行转换。最后,发布数据产品的组件需要支持集成,以便消费者可以轻松地将数据产品流式传输到自己的领域中,并遵循面向流式数据产品的联邦计算数据治理。表格2-1展示了四个数据网格支柱,在流式设置下的具体情况。
在本章中,我们将讨论在实现数据网格时,流处理相对于批处理的优势。我们还将介绍Kappa架构以及它如何实现这些优势。
流式数据网格相比批处理具有一些优势,通常在构建第一个用例之后才能体现出来。这些优势体现在技术实现和业务结果两个方面。
流式数据网格的第一个优势是它使数据消费域能够处理真正的实时用例。在数据产品中,流式处理是实现真正实时能力的唯一方式。如果数据流水线在从操作平面复制数据到消费域的过程中任何时候存储数据,那么就会剥夺所有潜在消费域的实时能力。当您在流水线的任何环节存储数据时,就会强制数据流水线具有批处理语义,包括使用类似CRON的工具来安排从数据存储中读取或一组读取的时间表。
即使现有的域目前没有任何实时用例,流式处理也支持批处理用例和实时用例。最好一开始就将数据流水线实现为流式处理。否则,不将数据网格实现为实时流式处理可能会导致巨大的技术债务,难以偿还。随着业务的发展,企业越来越注重数据驱动,并且对快速分析洞察的需求也会增加。即使今天没有任何实时用例,我们应该预期未来会出现实时用例。
流式数据设置了数据处理和人工智能的新标准。批处理引起的时间延迟使企业在应对业务需求上变得缓慢。当由于批处理而导致分析模型推理获得的洞察力变得延迟时,这个问题变得尤为重要,进一步导致收入损失或潜在客户的不满意。此外,模型的底层数据变化非常快。从过时的数据源训练分析模型会导致对不再代表被推断数据的模型进行推断(评分)。这种数据不一致性通常被称为训练和服务偏差,对于模型稳定性来说是一个具有挑战性的问题,因为在提供服务时没有准确考虑到数据的变化。考虑采用流式架构的一个关键动机是尽量减少训练和服务偏差。
当你从操作性存储中提取数据时,该数据被置于运动中。通过将其放入像Apache Kafka这样的流式平台中,数据保持在运动状态并通过分区和索引自动进行优化,从而实现高效的生产和消费。如果你将数据从流式平台中取出并存储到数据存储中,那么你将被迫重新优化数据,包括分区、索引、分桶或压缩,以便任何下游过程可以从数据存储中高效地消费数据。这引发了一个问题,如果数据处理尚未完成,为什么要将数据放入数据存储中。
图2-1显示了当数据从流式层中移除并放入数据湖中时会发生的情况。从流式中获取的实时数据几乎总是会在数据湖中创建小文件,因为数据是按事件流式传输的。
这些事件在集群上创建了较小的文件,而不是创建大文件进行批量上传(批量上传是批处理的特性,不能提供实时功能)。小文件是数据处理的绊脚石。除了存在块使用不佳的问题外,这种模式还有很多不利之处:
这是一个令人头疼的问题。解决方案是添加数据压缩和优化步骤,将所有小文件合并为较大文件。这个额外的步骤会减少文件数量,如图2-1中所示,在创建小文件之后的下一个步骤中。下游步骤最终到达数据仓库。添加数据压缩步骤最终会增加数据的延迟,使我们离实时数据处理架构的目标更远。结果,训练和服务之间的偏差增加,性能受到影响。
提取、转换和加载(ETL)是一种将数据从源移动到目标的过程,通常用于将数据从操作层移动到分析层。数据的移动类似于水流向下流入湖泊。参与ETL过程的所有技术系统都支持向湖泊自然流动,因为它们就是为此而构建和优化的。
相反,反向ETL(rETL)将数据以相反的方向移动:从分析层到操作层。公司之所以这样做,是因为他们的业务核心定义仅存在于数据仓库中,操作应用程序需要这些核心定义的数据:
Putting high-priced analytical database systems in the hot path introduces pants-on-head anti-patterns to supportability and ops. Who can say with a straight face that putting a data warehouse between two tier 1 apps is a good idea? Not many shops treat analytical systems—the data warehouse, ELT systems, offline feature stores, visualization systems—like tier 1, business-critical components. Eric Sammer, “We’re Abusing The Data Warehouse; rETL, ELT, And Other Weird Stuff,” Decodable, May 2022
反向ETL存在的问题是数据流的方向不自然。通过将原本在分析层的数据移动到上游,你实际上是逆流而行。支持正向ETL的系统被用于进行反向ETL。但是,这些系统更喜欢将数据下游移动,而不是上游。例如,数据仓库并不像操作数据库那样针对读取进行优化。它的优化目标是分析,用于为业务决策者提供洞察,而不是用于面向客户的应用程序的用户。
这就是流数据网格的优势所在。如果数据仓库中的数据已经在流平台中,它可以轻松被操作层使用,以提供给面向客户的应用程序。与数据流向数据仓库或湖泊的单向“流动”不同,流数据网格的隐喻更像是一个网格,其中允许每个方向的数据流动。
在我们讨论Kappa架构之前,我们首先需要了解它的前身——Lambda架构。这个模式最初由Nathan Marz和James Warren(Manning出版社)在大数据领域引入。其目标是在一个大数据系统上提供实时的使用案例。
Lambda架构是一个数据流水线,分为两个分支:实时流处理和批处理(见图2-2)。
这两个分支也可以被称为“在线”分支和“离线”分支。这是因为批处理分支需要一个能够存储历史数据的数据存储(很可能是数据仓库或数据湖)。实时或速度分支需要一个内存存储。为了更好地选择数据存储,最好遵循图2-3中的CAP定理。
对于Lambda架构的批处理分支,使用支持分区容错的数据存储以实现水平可扩展性,允许存储大量的历史数据。随着添加更多的数据,可以自动增加分区和节点,提高数据存储的计算和存储容量。在其他两个CAP特性中,对于批处理分支来说,可用性比一致性更为重要。这是因为一致性已经由流处理分支处理了。
当你拥有一个高可用的数据存储(图2-3中的可用性)时,可以实现更好的数据弹性,因为批处理源上的分区容错需要多个数据副本。在大多数常见的使用情况下,三个副本是标准,允许最多两个副本不可用而不会丢失批处理数据源。通过同时具备可用性和分区容错(AP),可以创建一个能够存储大量历史数据且在部分故障中不会丢失任何数据的数据存储。
对于流式分支,支持一致性的数据存储更为重要,因为它应该保存数据的最新状态。如果数据存储的分区之间存在不同的数据状态,就无法确定实时状态。在Lambda架构中,实时/在线数据存储负责构建实时视图。请参考表2-2中的历史事件作为键值对和表2-3中的实时视图。
请注意,历史数据(由批处理分支填充)和实时视图(由流式分支填充)不一致。在表2-2中的历史事件中,键3缺失,因为批处理尚未完成或开始将其填充到历史离线存储中。当批处理开始时,键3最终将出现在表2-2中。它还包含键1的两个版本,因为这是历史数据存储。 在表2-3中的实时视图中,键2缺失,因为它是24小时前添加的,不再存在于在线数据存储中。它包含键3,因为它是最近到达的,并将自动出现在在线存储中。 物化视图是持续更新的,而普通视图在查询执行时运行。
这个视图封装了每个键值对的最新状态。例如,如果将键=1且值为"foo"的记录发送到数据存储,然后立即发送另一个键=1且值为"bar"的记录,物化视图中的记录将是键=1且值为"bar",实际上是键的最新值。在Lambda流水线的最后,您需要将流式和批处理数据存储进行同步,以获得实时历史数据视图。当您尝试连接两个不同的数据存储时,这种同步变得棘手。最可能的是,同步将使用Python或基于JVM的语言编写。最终同步的表将类似于表2-4。
Lambda架构的批处理分支受到小文件限制的严重影响。始终需要进行数据优化步骤,以确保数据在并行处理过程中保持平衡;否则,大部分数据可能只经过少数几个处理过程,导致数据流水线花费更长时间。随着数据的增长,数据压缩和优化步骤将开始侵害与消费者达成的SLA协议。如果这些消费者是付费客户,这些优化问题将立即影响业务。
在Kappa架构中,必须在数据流水线的开始处考虑数据平衡。通过保持数据在整个数据流水线中的优化状态,直到达到目的地,可以避免数据压缩和优化步骤,而这些步骤可能需要几分钟甚至几小时才能完成。
Kappa架构是Lambda架构的简化版本,允许您只使用流式数据管道作为数据源。在Lambda架构中,历史数据是通过批处理管道从数据湖或数据仓库中读取的。那么在Kappa架构中,历史数据从哪里获取呢?在Kappa架构中,流式平台需要能够向其消费者返回历史数据。为了实现这一点,它要么通过在流式平台集群中添加更多的代理来扩展其存储能力,要么启用分层存储功能,将较旧的数据转移到代理之外的较低层中。推荐选择分层存储,因为它消除了通过添加更多代理来扩展流式平台的要求,这样做会增加成本。
如果不使用分层存储,流式平台将持续需要进行水平扩展活动以容纳所有历史数据,这也需要对所有数据的顶级存储进行扩展。以这种方式进行水平扩展还会向集群添加计算能力,而实际上并不一定需要这么多计算能力。扩展需要向流式平台添加更多的分区和代理,以及更多的提交日志(或分区),从而使数据分布在整个集群中。
分层存储提供了一种更简单和更便宜的方式来保存历史数据,但它需要改变流式平台与其消费者进行交互的方式,使其能够请求历史数据,而不仅仅是传统消息系统中的最新数据。这种改变展示了事件驱动与事件源的概念。
Kappa架构需要一个允许事件源的流式平台,而不仅仅是事件驱动架构,以便能够检索历史数据。在事件驱动架构(EDA)模式中,服务订阅状态的事件或变化。订阅的服务对事件变化进行操作。一个例子是一个人将其状态从单身更改为已婚。订阅了此状态变化的服务可能会向人力资源部门发送工资和福利变化的通知。
基本区别在于:流式平台可以无限地在提交日志中保存其数据。提交日志是Apache Kafka使用的一种数据结构。新数据始终追加到日志的末尾,且不可变(参见图2-4)。
事件驱动架构(EDA)的一个子集是事件溯源,如图2-5所示。EDA通常建立在消息传递系统之上。一些仅支持EDA的传统消息传递系统包括IBM MQ、RabbitMQ、ActiveMQ、Kinesis、Google Pub/Sub等等。所有这些消息传递系统都支持EDA。
提交日志可以配置为保留其数据,这提供了在流处理平台中进行有状态的连接和聚合操作的能力。以前,这些有状态的转换只能在数据库中进行,这意味着将数据置于静止状态,从而强制进行批处理语义。 此外,请注意,在关系型上下文中进行大规模的历史连接通常在性能和可扩展性方面存在许多问题。
通常,这些关系需要从磁盘中进行多次写入和读取,以满足查询输出的要求。而流处理允许用户或开发人员在适当的时间点在流中交集数据。 要实现流式数据网格,保持数据处于运动状态非常重要。这样做可以避免将数据写入数据存储时需要进行额外的数据优化步骤。这将使您能够在不必先将事件存储在数据库中的情况下执行实时的有状态转换(连接和聚合)。 数据中的每个记录都被分配了一个偏移量,以便数据消费者可以记住他们停止消费的位置,或者从特定偏移量重新播放记录。当启用无限存储时,这个提交日志将无限继续下去。在Apache Kafka中,流式数据存储在主题中,而主题由提交日志组成。提交日志用作将数据分区以便在数据处理中实现并行化的一种方式。
在本书中,“提交日志”一词在Apache Kafka的上下文中与“分区”一词是同义的。如果使用分层存储,则流处理平台将标记一条记录为冷集(较旧且不经常访问的数据),并将其迁移到较低层,同时将热集数据(较新且需要快速访问的数据)保留在更快的顶层。
在图2-6中,我们可以看到分层存储是如何在Confluent服务器中实现的。较低的存储层是对象存储,例如Amazon S3、Google Cloud Storage和Azure Blob Store。而顶层是Kafka代理中的存储。当应用程序请求超出热集范围的数据时,Confluent服务器会从对象存储中获取所请求的数据,并将其返回给应用程序。
流数据网格的优势对于数据产品工程师和数据产品消费者来说应该是有动力的。例如,数据工程师不再需要维护Lambda架构中的两个数据流水线,不再担心数据湖中的小文件问题,并且可以更一致地构建满足SLA的数据流水线。数据产品消费者不再局限于仅批处理的用例,可以更快地对业务做出反应并更好地服务于业务。在接下来的章节中,我们将讨论如何通过首先构建领域来构建流数据网格。
阅读量:2014
点赞量:0
收藏量:0