流数据库——部署模式本章将涵盖多个针对各种用例的部署模型。我们将重点探讨在何种情况下使用流处理数据库最具优势,以及何时其
本章将涵盖多个针对各种用例的部署模型。我们将重点探讨在何种情况下使用流处理数据库最具优势,以及何时其他方法可能更适合。我们会考虑到前几章中讨论的所有流处理属性,包括一致性、工作负载类型、存储格式,以及第9章中介绍的流处理层面相关概念。
我们将专注于解构各种支持流处理层面实时分析的架构模式。流处理层面的动态性质揭示了一系列独特的策略,以有效地利用其潜力。它可以支持一系列实时用例:
在光谱的一端,是那些与部署在操作层面的应用程序交互的用例。这些流处理解决方案需要一致性,但对历史数据的访问有限。 在光谱的另一端,是那些仅处理实时分析而不需要与应用程序逻辑交互的用例。这些流处理解决方案可以是最终一致的,并且可以访问所有历史数据。 当然,在光谱的不同位置,可以实现不同程度的一致性和历史数据访问。我们将涵盖整个实时分析光谱,从左端(一致性/内部一致性解决方案)到右端(仅分析)。
我们要特别强调的是,本章中的解决方案将使用“开箱即用”的流处理解决方案。这在一致性方面尤为重要。对于最终一致性的流处理数据库和流处理器,可以通过例如添加额外的字段并将其添加到连接逻辑中来“模拟”更强的一致性保证。实现这一点还需要对流处理平台有更深入的了解,这超出了本书的范围。然而,熟悉数据库但对流处理较新的工程师可能会期望更高的一致性,而无需后期模拟或附加。基于这种理解,更一致的解决方案可以在较少的努力下提供最高的价值。
一致性流处理数据库
当你需要一个能够运行复杂的异步/流处理并参与到应用程序逻辑中的数据库时,可以使用一致性流处理数据库来构建。此外,由于它也是一个数据库,你可以直接从流处理数据库中查询异步过程的输出。一致性流处理数据库可以简化你的基础设施,而无需深入了解流处理。满足此需求的解决方案包括RisingWave和Materialize。
在图10-1中,像RisingWave或Materialize这样的一致性流处理数据库展示了其混合特性,位于流处理层面和操作层面的边界上。
图10-1中的实线箭头表示流数据,虚线箭头表示应用程序与数据库之间的读写交互。一致性流处理数据库从OLTP数据库中消费数据,并通过流处理执行分析转换。结果保存在流处理数据库中的基于行的存储中。
这种解决方案允许应用程序直接写入OLTP数据库并从流处理数据库中读取数据。它还实现了读写数据资源的分离,使这些资源可以独立地进行扩展或缩减。
流处理数据库还提供了从多个OLTP数据库中消费和聚合数据的能力,并将转换后的数据发送到数据仓库或Lakehouse(即分析层面)。数据仓库将用于内部业务分析。
当面向用户的应用程序需要来自数据仓库或Lakehouse的历史数据时,这种解决方案的能力有限。由于数据引力,从分析层面接收历史数据是困难的。
当需要复杂的分析查询时,一致性流处理数据库也会遇到限制。这类查询更适合列式数据库。以下是与该解决方案相关的优缺点的综合表格:
优点 | 缺点 |
---|---|
能够在毫秒内提供数据新鲜度。 | 缺乏列式存储,而列式存储更适合快速的分析查询。 |
读写资源分离,资源可以独立且明确地进行扩展或缩减。 | 一致性流处理数据库在接收来自分析层面的历史数据时需要额外帮助,因为它们无法自行获取这些数据。 |
可以将多个OLTP数据库(即使是来自不同供应商的)输入合并到单个一致性流处理数据库中。 | 当数据量变得过大时,可能会遇到困难。 |
数据在发送到分析层面之前可以进行增量转换。 | |
在流处理数据库中使用相同的查询引擎/界面支持推和拉查询。 |
使用这种解决方案的场景应是需要参与应用程序逻辑的一致性流处理,而不需要(或只需少量)来自分析层面的历史数据。这也是从不同应用程序的多个OLTP数据库聚合数据的极佳方法。
一致性流处理器和RTOLAP
或者,如果你更倾向于将流数据输出到列式数据库中,可以使用像Pathway这样的一致性流处理器。一致性流处理器可以在接近操作层面的地方执行推查询,并参与应用程序的逻辑。它们将其输出写入像Kafka这样的流处理平台,RTOLAP数据库(如Pinot)可以从中消费数据并提供服务。
图10-2展示了如何在流处理器中转换数据,并将结果写入数据仓库/Lakehouse和RTOLAP数据库。RTOLAP还可以从数据仓库/Lakehouse(分析层面)读取历史数据,并将其与来自一致性流处理器的实时数据进行连接,然后作为低延迟拉查询提供给操作层面。以下是与该解决方案相关的优缺点:
优点 | 缺点 |
---|---|
可以在毫秒到秒的时间范围内提供数据新鲜度。 | 面向用户的分析可以包含所有历史背景,而无需将其存储在操作基础设施上。 |
RTOLAP数据库中的列式格式为应用程序提供了快速的分析工作负载。 | RTOLAP和流处理器可以重用流处理平台上的许多主题。 |
一致性流处理器可以扮演双重角色,既参与应用程序的业务逻辑,又为实时分析做准备。 | 推查询和拉查询分别在流处理器和OLAP数据库之间分离。这些查询的分离通常需要单独的工程师,并且需要严格的协调,这在实践中可能难以实现。 |
如果你的用例要求用户面对的分析需要使用大部分或全部历史数据,并且需要一个一致性流处理器参与应用程序逻辑,那么可以使用此解决方案。
最终一致性OLAP流处理数据库
如果将流处理器和OLAP数据库分开使基础设施过于复杂,那么利用像Proton这样的流处理OLAP数据库是一个很好的方法,可以将所有分析工作负载整合到一个解决方案中。但是,由于其最终一致性的特点,它不应参与应用程序的逻辑。在图10-3中,OLTP和流处理数据库之间的数据流动是单向的。应用程序可以利用OLAP的列式存储来实现低延迟查询。
由于Proton是一个流处理数据库,它具备将流处理输出写入Kafka的能力。这使得其他数据库可以消费这些分析流,以在其他数据库中构建副本。但由于Proton嵌入了ClickHouse(一个RTOLAP),它已经具备了列式存储功能,并能够以低延迟处理分析查询。将分析结果输出到Kafka还可以实现实时将分析分发到其他全球区域。以下是该解决方案的优缺点概览:
优点 | 缺点 |
---|---|
数据新鲜度可以达到毫秒到秒的级别。 | 仅为最终一致性;不应参与应用程序逻辑。 |
提供更多甚至全部历史数据,为实时数据提供更多上下文。 | |
Proton可以发出分析结果的更改,允许开发人员构建分析结果的副本。 | |
简化的解决方案,融合了流处理和OLAP技术。 | |
提供一个单一的SQL引擎来构建推和拉查询。 | |
体积较小。 |
使用流处理OLAP数据库的最大好处在于它能够在单一查询引擎和界面中平衡推查询和拉查询的能力。与需要单独的流处理器和OLAP数据库的解决方案不同,这减少了工程师的工作量,只需一个工程师即可。Proton为实时分析提供了一个简单的解决方案。
使用此解决方案可以减少基础设施和工程复杂性,并允许在用户面对的分析中访问更多历史数据。
最终一致性流处理器和RTOLAP
这种解决方案可能是当今提供实时分析最常见的方式。它通常涉及使用Flink和像Pinot这样的RTOLAP数据库。参见图10-4。
这种解决方案已经在许多高规模的实时应用中得到了验证:
优点 | 缺点 |
---|---|
数据新鲜度可以达到毫秒到秒的级别。 | 这是一个复杂且体积庞大的解决方案,可能导致更高的成本。 |
历史数据和实时数据可以结合在一起,提供完整的分析视图。 | 由于Flink是最终一致性的,因此不应参与应用程序逻辑。 |
由于流处理器和实时OLAP执行引擎是分离的,该解决方案无法提供一个用于推查询和拉查询的单一SQL引擎,这可能会导致更高的工程和组织压力。 |
当你的用例需要更多历史数据以用于应用程序中的用户面对分析时,可以使用此解决方案。在用维度流丰富事实流时,一致性不应是一个显著的关注点。
最终一致性流处理器和HTAP
在希望将分析工作负载保持在操作层面附近或其中的情况下,使用HTAP数据库与OLTP数据库结合可以非常方便。你可以添加一个最终一致性流处理器来捕获历史数据,并将其发送到数据仓库或Lakehouse。参见图10-5。
流处理器可以从分析层面获取有限的历史数据,并将其提供给HTAP数据库。由于其列式格式,它能够支持低延迟的分析查询。HTAP数据库通常保存的历史数据量有限,或者其保留时间有限。以下是该解决方案的优缺点:
优点 | 缺点 |
---|---|
提供毫秒级的数据新鲜度。 | 历史数据有限。 |
HTAP数据库具有列式存储,适用于快速分析查询。 | 在HTAP数据库中实施历史数据的保留会增加复杂性。 |
基础设施复杂性低。 | 流处理器无法参与应用程序逻辑。 |
当你的用例需要毫秒级的新鲜数据,并且只需要少量历史数据来支持用户面对的分析时,可以使用此解决方案。
ksqlDB
在第6章中,我们讨论了ksqlDB提供的一致性保证(“连续细化”,类似于“最终一致性”)。ksqlDB基于底层的JVM库Kafka Streams构建,适用于部署在微服务内部。微服务作为应用程序后端的一部分部署在操作层面。
我们建议仅将Kafka Streams和ksqlDB用于较简单的流处理操作。JOIN操作尤其难以正确实现,特别是当结合仅追加的“流”和类似变更日志的“表”时。ksqlDB仅支持部分SQL语法和语义(例如,不支持自连接、自嵌套连接)。尽管如果你有一支精通流处理的专家团队,ksqlDB是可行的,但实施不一致逻辑的风险仍然很高。
因此,ksqlDB的最佳用例是在Kafka上进行简单流处理操作(ksqlDB仅支持Kafka作为数据源和目标),以准备数据供数据仓库或数据湖等分析目的使用。还可以使用ksqlDB的物化视图来执行点查询,例如,为只支持批处理且无法使用完整的、持续运行的Kafka消费者的目标提供服务。在这种情况下,ksqlDB承担了消费者的角色,例如,为仅支持批处理的系统过滤和预处理数据:
优点 | 缺点 |
---|---|
数据新鲜度。 | 仅支持Kafka作为数据源/目标。 |
流处理能力。 | 需要大量的流处理专业知识。 |
通过使用物化视图(表格)支持点查询来支持仅批处理的目标。 | 复杂的流处理操作难以正确实现。 |
不支持完整的SQL语法和语义。 |
增量视图维护
支持IVM(增量视图维护)的解决方案,例如Feldera、PeerDB或Epsio,也可以用于支持基于批处理的点查询,处理经过预处理的新鲜数据。与ksqlDB不同,这些解决方案与操作数据库(如PostgreSQL)更紧密集成,不需要使用Kafka作为中间层。
此外,这些解决方案允许使用完整且一致的SQL语义进行更复杂的数据预处理。缺点是它们往往比基于Kafka的解决方案更不灵活。你基本上只能使用相应供应商支持的数据源和目标,而如果使用Kafka作为中间层,数据源和目标的选择范围会大大增加。
IVM解决方案还可以提高IT组织对异步和连续数据处理的理解,并作为他们进入流处理、流处理数据库世界的“入门药物”。它们仍然可以以相同的方式操作(例如PeerDB和Epsio),甚至可以在Postgres生态系统内部操作,但它们的操作方式已经接近流处理、流处理和流处理数据库——在更大的组织中集成更大的架构时,可能需要:
优点 | 缺点 |
---|---|
数据新鲜度。 | 受限于相应供应商支持的数据源/目标。 |
完整的SQL语法和语义。 | |
一致性。 | |
支持点查询。 | |
将流处理方面引入数据库世界。 |
Postgres Multicorn 外部数据封装器
Multicorn是一个PostgreSQL 9.1+扩展,旨在通过允许程序员使用Python编程语言来使外部数据封装器(FDW)的开发更加方便。这使得程序员能够为非Postgres数据库(例如Apache Pinot这样的RTOLAP数据库)构建FDW,并使数据可以在PostgreSQL数据库中使用。
如果你的操作层面数据库是基于Postgres的,Postgres的FDW绝对是将操作层面和分析层面更紧密结合的一种选择,而不会带来例如使用Kafka这样的流处理平台和中间的流处理所带来的复杂性。然而,类似于前一节中提到的IVM,Multicorn的问题在于它仅限于一个供应商。在较大的组织中,在99%的情况下,操作层面上会有大量的数据库技术——不仅仅是Postgres。因此,你需要将Postgres确立为中心操作数据库,这在大型组织中实际上是无法实现的。同样,使用Kafka作为中间层可能会有所帮助——如果你能承受这带来的额外复杂性:
优点 | 缺点 |
---|---|
完整的SQL语法和语义。 | 需要将Postgres作为中心数据库技术(在大规模部署/大型组织中不切实际)。 |
一致性。 | |
在Postgres生态系统内(操作层面)访问OLTP(Postgres)、其他非Postgres OLTP数据库和(实时)OLAP数据库。 |
何时使用基于代码的流处理器
数据的处理和查询也可以使用流处理数据库以外的技术来实现。经典的流处理技术如Kafka Streams和Flink仍然很有用,尤其是对于“硬核”流处理用例,如欺诈检测或在微服务架构中的应用,这些通常位于操作层面。
近年来,基于代码的流处理技术也显著增长。现在,除了经典技术外,你还可以选择如Quix Streams(Python、C#)、Bytewax(Python)和Pathway(Python)等技术。有趣的是,Bytewax和Pathway都基于与Materialize使用的相同的流处理引擎(timely dataflow/DD)。其他新兴且有趣的技术包括Deephaven和一个基于Python的框架GlassFlow。
何时使用Lakehouse/Streamhouse技术
Lakehouse技术,如Databricks的Delta Tables、Apache Iceberg或Apache Hudi,也越来越多地进入流处理领域,提供流处理和/或流处理功能。实际上,Databricks从一开始就提供了这些功能(Spark Structured Streaming)。Ververica提出的新Streamhouse架构通过Apache Paimon提供了流处理与数据湖处理的更紧密集成。稍后,Confluent宣布了Tableflow功能,使其可以在其基于Kafka的流处理平台Confluent Cloud上以Iceberg表的形式公开数据。与Paimon类似,Confluent使用Flink无缝集成流处理和批处理。
与Tableflow类似的解决方案来自初创公司Streambased.io。它构建了一个查询Kafka主题的解决方案,一方面与Kafka紧密结合,另一方面提供了一个基于Trino SQL查询引擎的类似数据库的SQL接口。如果你在没有Streambased的情况下使用Trino在Kafka上运行查询,查询的性能可能会非常低,因为查询引擎直接从Kafka主题中读取数据。Streambased为Kafka主题添加了基于Bloom过滤器的索引,用于提高基于Trino的查询性能,通常可提高10倍或更多(该公司在其网站上声称可提高39倍)。
与Pinot、Druid或ClickHouse等RTOLAP数据库相比,Streambased不复制Kafka数据,而是仅创建附加索引——这些索引占用的磁盘空间远少于实际数据。通过索引提高的性能使你几乎可以“直接”以非常低的延迟查询Kafka主题。这可能是另一种实现流处理和批处理“向下兼容”的解决方案,你实际上可以通过REST或JDBC(Java数据库连接)查询Kafka主题,就像它们是数据库表一样。这可以通过使流处理几乎对最终用户不可见,从而使流处理更易于访问。
从本质上讲,所有这些发展都增加了流处理层的数据引力。可以在更接近流处理或数据流动的位置进行更多处理,而在数据仓库/数据湖中需要实现的处理减少。如果数据的新鲜度/延迟不是主要关注点,数据的处理可以无缝地从流处理层迁移回分析层(反之亦然,如果延迟变得更为重要)。
缓存技术
当然,还有更多选择。如果你需要比使用Kafka等流处理平台更低的延迟,可以考虑缓存工具如Redis或Hazelcast。根据它们与流处理平台的集成程度,这些工具可以位于操作层面或流处理层面。像Hazelcast这样的解决方案甚至提供类似流处理的功能,例如使用类似SQL的语法。
一般来说在哪里进行处理和查询?
在本书中,我们引入了大量技术,有些技术位于操作层面,有些位于分析层面,有些位于流处理层,且大多数处于这些层面之间的某个位置。
作为本书的读者,你很可能是一个实践者。你有任务要完成,可能正在阅读本书以获得新的想法来实现这些任务。那么我们,作为本书的作者,能否在这方面提供帮助?有没有一些更通用的建议可以帮助你选择正确的方法和技术,以及如何分布和扩展它?
当然,像这样的问答中最保险的回答是“这取决于具体情况”。确实如此,但我们希望能提供更有帮助的建议。本节内容是关于“取决于什么”以及选择特定技术可能会带来哪些后果的讨论。
四个“在哪里”问题
当你考虑某个任务或用例时,哪些因素最关键地决定了实现此任务的技术选择?让我们回顾一下我们的“地图”或“数据空间的景观”,它被安排在操作、分析和流处理层面重叠的Venn图中。这张地图可能会促使我们首先考虑位置,然后从那里出发。
因此,当你考虑你的任务或用例时,试着问自己以下四个“在哪里”问题:
- 我的用例位于哪里?
- 我需要的用于用例的数据在哪里?
- 我在哪里处理它?
- 我在哪里查询它?
一个分析用例
图10-6展示了一个典型的例子。考虑一个分析用例,其中来自操作系统的数据需要在一个面向业务的仪表盘应用程序中查询。因此,第一个问题的答案(“我的用例位于哪里?”)是“分析层面”。假设第二个问题也很容易回答——数据的来源是流处理层的一个流处理平台。在图中,观察从数据来源(问题2的答案)到用例(问题1的答案)的箭头。
让我们引入接下来的两个“在哪里”问题:我在哪里处理数据?我在哪里查询数据?在当今世界中,典型的答案通常是“在分析层面上同时进行”,例如在像Snowflake这样的数据仓库或像Databricks这样的Lakehouse技术中。
但也许如此简单(且可能昂贵)的答案并不适合你。对我们来说,它并不是唯一的答案,因为对于问题3和4,当然不只有一个答案。实际上,有一个连续的答案范围。
让我们关注从问题2到问题1的直线或“路径”。这条路径表示了问题3和4的答案范围。当然,你可以给出简单的答案,同时在分析层面处理和查询数据,如图10-7所示。
然而,你也可以考虑其他选项。例如,你可以使用一种技术来回答问题3(“我在哪里处理数据?”),使你能够在流处理层上进行处理,例如使用像Flink这样的流处理器或流处理数据库。如果你使用流处理数据库,还可以将数据查询(问题4)推到流处理层,如图10-8所示。
所以,基本上,将你的用例位置与数据来源位置连接的路径,指定了可能的位置范围或技术选项,也就是你可以用来解决任务的一系列可能位置。你可以在这条路径上的任何位置进行数据处理和查询,但你的选择总会带来正面和负面的影响。
后果
这些后果是什么呢?理论上,离数据源越远的位置进行处理(问题3)和查询(问题4),你遇到的劣势就越多。当然,这与我们在前几章中讨论的数据引力理论密切相关。例如,如果你像图10-7那样回答问题3和4,并且都在分析层面上进行,那么你会面临以下挑战:
- 保持数据新鲜度:因为数据需要先传输到分析层面,然后才能进行处理和查询。
- 共享处理后的数据:因为处理紧贴着用例执行,所以数据的共享会更加困难。
- 增量处理:在分析层面上,批处理很常见。为了使处理生效,数据需要反复处理同样的数据,这种方法效率低下,尤其是在使用云数据仓库技术时,这可能会非常昂贵。
那么,为什么绝大多数行业仍然选择这样做呢?为什么问题3和4的答案大多数情况下都是“在分析层面上完成”?对于这个非常常见的用例,考虑到我们列出的这些劣势,为什么流处理层的引力仍然如此低,而分析层的引力如此高呢?
我们认为,对这种存在诸多缺点的架构的普遍接受,其中一个主要原因是流处理(以及流查询)仍然很困难。至少在以下三个方面,流处理是困难的:
- 需要大量的流处理专业知识,而这些知识通常并不易得。
- 即使有流处理专家,流处理仍然是成本密集型的,事实上,这种成本可能会超过通过更早和增量处理所节省的潜在成本。
- 即使具备流处理专业知识,也很难从流处理过程中获得一致的结果。
相反地,我们可以说,越早进行处理,数据就会越新鲜,处理后的数据就越能被共享,数据的增量处理能力也就越强。但在流处理数据库出现之前,出于实际考虑,使用流处理往往并不可行。
流处理数据库有潜力改变这一现状,因为它们的工作方式与普通数据库非常相似。例如,Materialize 和 RisingWave 甚至使用了 Postgres 的传输协议。MongoDB 中的新流处理引擎也可以轻松被 MongoDB 专家使用。因此,在这两种情况下,都不需要太多流处理方面的专业知识。基本上,你可以让现有的数据库/数据仓库专家来完成这项工作,从而大大降低流处理的实施成本:不需要额外雇用专家。
当谈到第四个“在哪里”问题——关于数据查询时,新一代流处理数据库甚至提供了几乎直接查询流数据的能力,它们通过提供物化视图实现这一点。不断更新的物化视图提供了更新的数据,而通过在底层使用增量流处理,也可以降低用例实现的成本:因为只需要处理新数据(然后将其物化)。针对物化视图运行查询可以避免反复遍历相同的旧数据点。特别是在高频查询的情况下,这可以减少计算需求,从而显著降低成本。
因此,流处理数据库实际上可以成为流处理普及的改变者,有可能增加流处理层的数据引力。对于很多用例,至少处理(问题3)可以在流处理层上完成,这在流处理数据库出现之前是无法实现的。
当你将这一思路与最近出现的技术(如Streamhouse(Ververica)和Tableflow(Confluent))结合起来考虑时,流处理层的数据引力将进一步增加,而我们Venn图中三个层面之间的界限将继续模糊。
总结
本章讨论了流处理数据库和其他徘徊于操作、分析和流处理层之间的混合技术的各种部署和架构模型,并分析了基于这些技术构建架构的优缺点。
我们接着讨论了与本书总体主题关系较弱但仍值得提及的技术,包括基于代码的流处理解决方案、Lakehouse中的流处理新发展以及缓存技术。
我们通过一系列“在哪里”的问题来概括我们的部署模型建议。基于本书后几章中使用的Venn图,我们开发了这些问题,以帮助你划定处理和查询数据的位置的可能性范围。
我们得出结论,流处理数据库实际上可以推动流处理的普及化以及流处理的普遍应用。因此,它们有可能大大增加流处理层的数据引力。随着越来越多的流处理供应商(如Ververica的Streamhouse和Confluent的Tableflow等)和非流处理供应商(如MongoDB、Databricks等)提供的功能,这种趋势将进一步增强,这些供应商在我们的Venn图中与流处理层重叠的部分中的地位越来越显著。
在下一章,也是最后一章中,我们将进一步详细探讨流处理与数据库融合的这一令人兴奋的思路。
转载自:https://juejin.cn/post/7402776273166663717