流数据库——实时数据服务在第2章中,我们让流处理平台对数据进行了转换并将其放入了汇主题中。预处理后的数据现在驻留在流处理
在第2章中,我们让流处理平台对数据进行了转换并将其放入了汇主题中。预处理后的数据现在驻留在流处理平台的一个主题中。在图3-1中,汇主题和 OLAP 数据存储在分析层中被突出显示。
接下来我们需要做的是将实时数据提供给消费者。在本章中,我们将讨论如何将丰富的实时数据传递给最终用户。这是实时数据管道的最后一步,流数据在呈现给最终用户之前会经过这个阶段。
实时预期
为了将实时分析服务提供给我们识别的消费者(包括人类和应用程序),需要考虑一系列服务水平协议 (SLA)。在我们的点击流用例中,我们并没有为最终用户或应用程序指定要求。然而,既然我们希望实时提供分析服务,就应该考虑以下一些指标:
- 延迟 测量分析查询或计算完成并返回结果所需的时间。在实时分析中,低延迟对于向用户提供近乎即时的见解至关重要。SLA 指标可能会定义可接受的延迟阈值,例如平均响应时间或最大响应时间,以确保及时交付分析结果。
- 吞吐量和并发性 测量在给定时间范围内可以处理的分析查询或计算数量。它表示系统处理并发请求的能力,特别是在高容量场景中非常重要。SLA 指标可能会指定目标吞吐量,例如每秒查询数或每分钟计算数,以确保能够满足实时分析工作负载的需求。
- 数据新鲜度 表示分析结果与底层数据流的最新程度。它测量数据生成与数据可供分析之间的延迟。SLA 指标可能会指定可接受的数据新鲜度要求,例如最大延迟时间(以秒或分钟为单位),以确保用户能够访问最新的信息。
- 准确性 测量分析结果的正确性和精确度。SLA 指标可能会定义可接受的错误率、置信区间或验证标准,以确保实时分析的准确性。
在为消费者提供实时分析服务时,上述指标对实时需求的影响最大。其他指标与容量大小、数据弹性和安全性有关。我们将在本书的后续章节中更多地关注这些其他 SLA 指标。这些 SLA 指标包括:
- 可用性 测量实时分析系统的正常运行时间和用户访问的可用时间百分比。SLA 指标可能会定义系统的预期正常运行时间或停机时间,考虑计划维护窗口和意外中断。高可用性对于提供持续的实时分析访问能力至关重要。
- 一致性 确保结果在不同查询执行和系统副本之间是一致的指标。
- 可扩展性 测量实时分析系统处理数据量增加、用户请求和计算复杂性增加的能力。SLA 指标可能会指定性能基准或容量阈值,以确保系统能够横向或纵向扩展,以满足日益增长的需求。
- 安全性和隐私性 SLA 指标可能包括安全性和隐私性要求,以确保数据保护、访问控制、加密和法规遵从性。这包括防止未经授权访问、保护敏感信息以及维护数据完整性。
我们需要选择最合适的数据库来提供符合实时相关 SLA 的数据:延迟、并发性、新鲜度和准确性。
选择分析数据存储
根据用例的具体要求和限制,有几种类型的数据存储可以满足实时分析的 SLA。再次强调,我们的用例并未为实时分析指定 SLA,但点击流用例通常需要非常低延迟的查询,以跟踪并响应库存变化,如动态补货、动态定价、库存重新分配和分配以及预测分析等。
以下是一些可以满足这些严格实时 SLA 的数据存储示例:
- 内存数据库,如 Redis、SingleStore(前称 MemSQL)、Hazelcast 或 Apache Ignite,将数据存储在内存中以实现快速访问和处理。这些数据库提供极低的延迟和高吞吐量,使其适合需要近乎瞬时响应的实时分析。
- RTOLAP 数据存储,如 Apache Pinot、Apache Druid、ClickHouse、StarRocks 和 Apache Doris。这些数据存储通常是面向列的分布式数据存储。它们按列而不是按行组织数据,从而实现高效的分析和查询处理。这些数据库可以处理大量数据,并提供出色的可扩展性和高可用性,使其非常适合大规模实时分析。
- 混合事务/分析处理 (HTAP) 数据存储,如 TiDB 或 SingleStore(前称 MemSQL),支持在单个系统中同时进行实时事务处理和分析处理。这些数据库能够直接在操作数据上提供实时分析,最大限度地减少数据移动并降低延迟。
从数据仓库、数据湖或湖仓中提供数据将无法实现前述与库存相关的用例所需的实时 SLA。
注意
有争议的是,术语“数据库”通常指的是 OLTP 数据库。如果你还记得,OLTP 数据库通常是事务性的、基于行的,存在于服务用户界面应用程序的操作数据层上。那些同意这一前提的人喜欢将“数据存储”用于服务分析查询的系统。我们将遵循这些定义,并可能在本书中交替使用它们。
前述提到的一些数据存储通常部署在分析数据层,这与 OLAP 风格的数据存储一致。其他数据存储则仅部署在操作数据层,如 HTAP 数据库,我们将在第7章中更深入地讨论。在本章中,我们将使用传统上用于实时分析用例的 RTOLAP 数据存储。使其成为实时的是它们能够从像 Kafka 这样的流处理平台中的主题获取数据。
从主题获取数据
在图3-1中,你看到我们的用例的实时数据已经过预处理并放入了像 Kafka 这样的流处理平台中的一个汇主题中。流处理平台提供了一种发布和订阅模型,用于分发流数据,这意味着其他系统、领域和用例可以从汇主题中消费相同的数据。流处理平台中的预处理工作可能只将数据准备到所有消费者都可以使用的程度,以一种符合他们的共同标准的数据格式。这使得任何特定消费者的数据准备工作由消费者自行实施。图3-2展示了这种情况。
例如,假设域消费者1需要数据中的时间戳以秒为单位,而域消费者2则需要数据以年-月-日格式表示。在流处理平台中实施转换的工程师可以决定以毫秒为单位提供时间戳,这样两个消费者都可以从中提取他们需要的时间戳格式。这也将满足任何未来需要以毫秒为单位获取数据的消费者的需求。
这些场景要求查询在实现转换时将时间戳值转换为他们所需的格式。不幸的是,这种转换会减慢查询的速度。每次查询运行时都需要执行这个转换,最终可能会打破延迟的SLA(服务水平协议)。这最终会导致应用程序或仪表板变慢,给数据消费者带来不满意的体验。任何留给消费者自行实施的特定数据准备工作都会影响提供实时分析服务的SLA。
图3-3中展示了这种情况。
摄取转换
在许多实时在线分析处理 (RTOLAP) 系统中,有一个功能可以在流数据到达持久存储之前对其进行预处理。这为 RTOLAP 提供了一种在数据仍在传输时转换流数据的方式。在时间戳的用例中,从主题中消费的数据可以通过一组无状态的转换处理,例如将毫秒转换为年-月-日格式。
摄取转换类似于无状态的流处理器。在后续章节中讨论物化视图时,记住这一点非常重要。主题中的数据消费者被迫将这些数据视为一种基础格式,从中派生出他们所需的格式。
大多数这些 RTOLAP 数据存储只能在实时数据存储之前进行无状态的预处理,尽管有些已经在考虑将有状态转换作为摄取过程的一部分。
Apache Pinot 是一种能够在摄取时执行有状态转换的 RTOLAP 数据存储的示例。Pinot 拥有一个综合的索引列表,使得 Pinot 查询能够在非常低的延迟下执行。其中一个索引被称为星形树索引。星形树索引的优势在于它能够预处理需要保持状态的聚合操作。这实际上是在摄取时发生的有状态转换。我们将在本章后面更多地讨论索引及其重要性。
在 RTOLAP 数据存储中,有状态的摄取转换变得越来越常见,可以将数据从基础格式转换为首选格式。在未来的用例中,RTOLAP 中的有状态摄取转换可能会与其他表进行连接,以在 RTOLAP 中提供非规范化视图。非规范化视图在提供分析查询时性能更高,因为在持久化数据之前只执行了一次连接。这比用户提交连接查询更加优化,因为连接查询会在每次查询请求时发生。
注意
非规范化视图,也称为“一张大表”(One Big Table,OBT),指的是一种将多个表中的信息组合并整合为单个表或视图的数据组织方式。通常情况下,数据被分割到多个表中,每个表代表一个特定的实体或关系,以确保数据完整性并减少冗余,从而最终节省存储空间。然而,在某些分析场景中,将相关数据合并到非规范化视图中可能更高效。非规范化的合并视图简化了查询和分析,因为所有必要的信息都集中在一个地方,消除了在表之间进行复杂连接的需求。如果管理不当,非规范化视图会引入冗余,并可能影响数据完整性。
摄取转换和流处理的行为非常相似,因为它们都是在后台运行的异步过程。异步过程与用户不进行交互,而是由用户定义并运行,但不等待结果返回。我们将在本章稍后回到异步和同步过程的讨论。
摄取转换不仅格式化数据,还优化它以便快速分析查询。其中一种优化是使用列式(或基于列的)格式,许多像 Pinot 这样的 OLAP 系统都利用了这一点。列式格式通常不用于 OLTP 数据库,后者采用基于行的格式。我们将在本章中对此进行更详细的讨论。
OLTP 与 OLAP 的对比
将 OLTP 数据库与 OLAP 数据存储进行对比有助于理解如何提供数据服务。
回想一下,OLTP 数据库用于操作平面的事务工作负载。它们向面向用户的应用程序返回记录,设计目的是高效地处理和管理实时的事务操作。它们主要用于支持日常业务活动,这些活动涉及频繁的数据交互,如创建(插入)、检索、更新和删除数据记录。这也被称为 CRUD 操作:创建、检索、更新和删除。
OLTP 数据库的主要目的是确保在事务处理期间数据的完整性和一致性。它为订单处理、库存管理、金融交易和客户互动等操作任务提供快速可靠的数据访问。OLTP 数据库针对大量并发事务进行了优化,通常允许多个用户同时访问系统。
这些数据库通常具有规范化的数据结构,旨在最小化数据冗余并保持数据一致性。它们优先考虑事务能力,支持 ACID 属性(原子性、一致性、隔离性、持久性),以确保数据处理的可靠性和安全性。
ACID
ACID 是一个首字母缩略词,定义了一组确保在 OLTP 数据库中执行事务时数据可靠性和一致性的属性:
- 原子性 (Atomicity): 可以将事务看作一个不可分割的单一操作。原子性意味着事务被视为一个整体,要么其所有更改都成功应用,要么完全不应用。它确保了即使在事务过程中出现问题,数据库仍然保持一致状态。
- 一致性 (Consistency): 一致性确保事务将数据库从一个有效状态转换为另一个有效状态。它意味着数据库中定义的任何规则、约束或关系在事务期间和之后都得到维护。简而言之,数据库保持在一个合理且预期的状态,因此当许多客户端从数据库中检索记录时,它们都能看到一致的视图,并且记录也是一致的。
- 隔离性 (Isolation): 隔离性意味着多个事务可以并发发生而不相互干扰。每个事务在完成之前都与其他事务隔离,防止冲突并确保每个事务都能看到一致的数据库视图。
- 持久性 (Durability): 持久性保证一旦事务成功完成,其更改将被永久保存,并在后续的系统故障或崩溃中幸存下来。更改成为数据库的永久组成部分,并可靠地存储以供将来使用。
ACID 合规性确保了数据库事务的可靠性、一致性、相互隔离性和持久性,为数据的完整性和可靠性提供了坚实的基础。
相反,OLAP 数据存储用于分析平面的分析工作负载。它们采用与 OLTP 数据库不同的优化技术。每种数据存储类型都针对其应发挥的角色进行了优化。
基于行与基于列的优化
我们在本章前面介绍了基于行与基于列的格式。这些格式是数据库中组织和存储数据的两种不同方式。
在基于行的格式中,数据按行存储和组织。这意味着某一行的所有列数据存储在一起,然后存储下一行的数据,依此类推。这种格式类似于电子表格中数据的传统表示方式。它针对事务处理进行了优化,适用于频繁更新或插入单行数据的场景。
在基于列的格式中,数据按列存储和组织。这意味着某一列的所有值存储在一起,然后存储下一列的值,依此类推。这种格式针对分析处理进行了优化,适用于查询通常涉及聚合、过滤和分析特定列或数据子集的情况。表 3-1 列出了更多区别。
当实时流数据到达服务层时,预期已对其进行了准备,以便快速进行分析查询,因为服务层位于分析平面中。列式存储将为分析查询提供最佳的查询性能和效率。
表 3-1. 基于行与基于列的优化区别
属性 | 基于行 | 基于列 |
---|---|---|
数据存储 | 在基于行的格式中,每一行的数据存储在一起。基于行的格式会影响查询时数据的访问和读取方式。不建议用于分析查询。 | 在基于列的格式中,每一列的数据存储在一起。基于列的格式提供更好的优化,支持分析查询。 |
查询性能 | 基于行的格式通常更适合涉及检索整个行或更新单行的事务操作。 | 基于列的格式在分析操作中表现出色,因为它们允许更快的数据检索和特定列或数据子集的处理。 |
压缩 | 基于行的格式提供了一些压缩技术,如空值压缩、运行长度编码、字典压缩和数据类型特定压缩。压缩技术在数据读取和写入操作期间引入额外的计算开销,因此压缩算法的选择和配置需要根据数据库系统的特定工作负载和性能要求进行平衡。 | 基于列的格式通常提供比基于行的格式更好的压缩比。由于列通常包含重复信息,压缩技术可以更有效地应用,从而减少存储需求。 |
查询效率 | 基于行的格式可能需要读取整个行,即使只需要几列,这可能导致更高的磁盘 I/O 和较慢的查询性能。 | 基于列的格式旨在仅读取和处理特定查询所需的列,最小化磁盘 I/O 并提高查询性能。 |
每秒查询次数与并发性
每秒查询次数(Queries per second, QPS)是衡量 OLAP 数据存储返回查询结果能力的指标。这反过来表明了 OLAP 在一秒钟内能够处理的查询量,最终反映了可以调用的并发查询数量。
在我们的点击流用例中,我们没有明确说明有多少最终用户可能会查看分析结果。假设每个最终用户至少会有一个查询。我们已经指出这是一个实时用例,因此仪表板上的数据新鲜度预期是实时的。实时仪表板往往需要高频率的刷新,以尽可能保持仪表板上的图表实时更新。每次刷新仪表板时都会产生一个查询。
对于 1000 名查看点击流分析的用户,如果仪表板的刷新率为每 5 秒一次,你将得到以下公式:
1000 用户 × 1 查询/5 秒刷新 = 200 QPS 需求
这意味着查询需要在 5 毫秒内完成。我们可以通过取倒数将 200 次查询/秒转换为毫秒/查询:
1/200 查询/秒 = 5 毫秒/查询
你需要测试单个查询,看看 OLAP 数据存储是否能够在 5 毫秒内返回结果。对于仅 1000 名最终用户来说,这个要求很高。如果该仪表板由外部用户使用或在手机应用程序上使用,你可能会超过 1000 名最终用户。此外,你可能也不希望将业务限制在仅 1000 名用户上。你将需要扩展 OLAP 集群以适应更多用户,或简化查询,以便它能够在 5 毫秒内返回结果。你还可以应用更好的索引策略。
索引
索引在提高 OLAP 数据库的 QPS 方面起着关键作用。战略性地应用索引将有助于在不扩展 OLAP 集群的情况下提高 QPS,从而避免增加硬件需求和成本。
所有 RTOLAP 数据存储都使用一组索引来帮助提高 QPS。它们有多种帮助方式。例如,索引使数据库能够更快地定位和检索相关数据。通过在常查询的列上创建索引,数据库可以避免扫描整个数据集,直接访问索引的值,从而显著减少查询响应时间,并提高 QPS。
索引还提供了查询优化器可以用来确定最有效查询执行计划的有价值的统计数据和元数据。这有助于优化资源分配、数据检索策略和连接操作,从而最终提高整体查询性能并增加 QPS。
剪枝是一种性能技术,它允许 OLAP 剪除没有结果的数据块。这种方法根据特定列值缩小了搜索范围。这种选择性访问消除了扫描整个数据集(或省略大部分数据集)的需要,使得数据库能够在给定时间内处理更高量的查询,从而也增加了 QPS。
索引还提供了一种数据结构,在查询处理期间组织数据,从而减少磁盘 I/O 操作。通过减少所需的磁盘读取次数,索引最小化了访问数据所花费的时间,从而提高了 QPS。
以下是 RTOLAP 数据存储中索引的具体示例,Apache Pinot 支持多种索引类型以优化查询性能。表 3-2 显示了 Apache Pinot 中一些最常用的索引类型。
表 3-2. 基于行与基于列的优化区别
索引类型 | 描述 | 使用场景 |
---|---|---|
位图索引 (Bitmap index) | 位图索引适用于低基数列(具有少量不同值的列)。它们为每个不同的值创建一个位图,指示该值在每行中的存在或不存在。位图索引在过滤和聚合操作中非常有效。 | 低基数列 |
排序索引 (Sorted index) | 排序索引按顺序存储列的值。它们特别适用于基于范围的查询,并能进行高效的过滤和排序操作。 | 日期、时间戳 |
倒排索引 (Inverted index) | 倒排索引适用于高基数列(具有大量不同值的列)。它们将每个唯一值映射到包含该值的相应行集。倒排索引对等值和前缀搜索非常有效。 | 高基数列 |
正向索引 (Forward index) | 正向索引按数据中出现的顺序存储列的原始值。它们对需要获取原始值而不进行特定过滤或聚合的查询非常有用。 | 不用于过滤或聚合的列 |
文本索引 (Text index) | 文本索引专为全文搜索场景设计。它们能够基于关键字、短语或其他文本标准进行高效搜索。 | 用于高效搜索的文本列 |
这些索引可以单独使用或组合使用,具体取决于数据的性质和特定查询模式。在 Apache Pinot 中,为每一列选择合适的索引在优化查询性能中起着至关重要的作用。
需要注意的是,尽管索引可以显著增强查询性能和 QPS,但必须在索引的数量和大小之间取得平衡,因为过多的索引可能对插入、更新和删除操作产生负面影响。适当的索引策略和定期的索引维护对于 OLAP 数据库的最佳性能至关重要。
正如本章前面所述,星树索引 (star-tree index) 可以预处理需要保持状态的聚合操作。这实际上是一种在摄取时发生的有状态转换。
星树是一种用于基于其基数对多个字段进行排序和预聚合的索引技术。它旨在加速大数据集上的聚合和计算密集型查询。星树索引的操作类似于树结构,每个级别对应于数据集中用于过滤和聚合数据的字段(见图 3-4)。树的根代表星号(或通配符),它跨这些字段聚合度量。每条从根到叶节点的路径表示字段值的组合及其对应的聚合度量。
让我们进行一个简单的示例,看看星树索引是如何工作的:
-
查询从根节点开始,向下遍历到第一个维度(D1)。星树的维度是按基数从高到低排序的。在这种情况下,D1 是一个具有最高基数的列。
-
如果 SQL 条件是
where D1 = V2
,则记录会在 D1 维度的 V2 节点下被聚合:- 查询路径 = Root → V2 扫描
-
如果 SQL 条件是
where D1 = V1
,则查询会进入第二维度下的 “V1” 星节点,并返回预聚合的值:- 查询路径 = Root → V1 → 星节点预聚合
-
如果 SQL 条件是
where D1 = V1 and D2 = V1
,查询会扫描 D2 维度下的 V1 记录:- 查询路径 = Root → V1 → V1 扫描
-
如果条件是
where D2 = V2
,查询路径会进入 D1 维度的星节点,因为 D1 没有被过滤。然后查询会进入 V2 节点并扫描其记录:- 查询路径 = Root → 星节点 → V2 扫描
-
最后,对于没有条件的查询:
- 查询路径 = Root → 星节点 → 星节点
-
-
星树配置的一部分是提供一个分割阈值,以限制扫描的记录数量。如果你设置了 100,000 的分割阈值,星树索引将确保你的查询永远不会扫描超过 100,000 条记录。
-
星树索引在段生成阶段创建后构建。在 Apache Pinot 中,段是一个逻辑抽象,表示包含一定数量行的表数据块。段以列存储方式存储表的所有列数据,并为这些列生成字典和索引。
注意: 段类似于关系数据库中的分片或分区,也可以视为基于时间的分区。它们允许 Pinot 的分布式架构通过将大量数据分解成较小的、可管理的数据块来实现水平扩展,这些数据块随后会分布在多个节点上。
星树索引在数据被摄取时就对其进行聚合,以便后续查询可以利用这些聚合结果。这种优化活动类似于流处理平台中执行的预处理工作。将预处理内置到 OLAP 数据存储中变得越来越普遍,因为将数据优化为列格式、索引优化以及像时间戳重格式化这样简单的转换工作几乎是不可避免的。OLAP 数据存储在实现实时数据的有状态流处理方面极其依赖。
通过提供一种方式在 OLAP 中定义有状态的摄取转换,用户可以编写额外的预处理逻辑,该逻辑只执行一次,而不是在每次执行分析查询时重复执行(见图 3-5)。
用户可以在数据摄取阶段使用 SQL 或一组函数来定义单独的摄取命令,从而简化分析查询阶段的 SQL,提高执行效率,降低延迟,并最终提高 OLAP 数据存储的 QPS。这种技术还可以减少扩展 OLAP 集群的需求,因为它降低了分析查询需要执行的工作量。
服务分析结果
正如前面提到的,QPS 是衡量用户或应用程序发出的查询性能的一个重要指标。尤其是在实时使用场景中,分析查询通常需要较高的刷新率。高刷新率可能会对 OLAP 系统造成压力,这种情况也被称为轮询。
同步查询
我们之前描述的分析轮询查询也称为拉取查询,因为用户或应用程序(客户端)会提交查询并从 OLAP 系统中拉取数据。它遵循请求-响应模式。
客户端通过驱动程序和方言提交查询。方言提供了一种客户端和 OLAP 之间使用特定于 OLAP 系统的 SQL 变体进行通信的方式。
异步查询
分析数据也可以通过异步方式提供。这种类型的查询称为推送查询,因为数据会被主动推送到客户端。推送查询的优势在于,不再需要测量 QPS,因为这是严格的拉取查询性能指标。推送查询的客户端会在收到新分析数据时得到通知,因此不再需要轮询。
推送查询最有可能从流媒体平台中的主题(topics)提供。客户端可以订阅这些主题,并在接到通知时重新填充他们的实时应用程序或仪表板。
服务如 Aklivity/Zilla 提供了异步 API,允许客户端使用 Server-Sent Events (SSEs) 或 WebSockets 订阅异步分析数据。SSE 和 WebSocket 是用于客户端(通常是 Web 浏览器)与服务器之间实时通信的技术。虽然它们都支持实时更新,但它们之间有一些关键区别:
- 单向通信:SSE 允许服务器向客户端浏览器推送数据,提供一个单向通信通道。客户端从服务器接收更新或事件,但不能通过相同的连接发送数据回去。
- 事件流格式:SSE 使用特定的事件流格式将数据传送到客户端。服务器将数据作为一系列事件发送,客户端使用 JavaScript 处理这些事件。事件流格式包括事件类型、数据和可选字段,如 ID 或时间戳。
- HTTP 协议:SSE 建立在 HTTP 协议之上,并使用标准的 HTTP 连接。这会在客户端和服务器之间建立一个长连接,通常使用单个 HTTP 连接来进行多次更新。
- 浏览器兼容性:SSE 得到了大多数现代 Web 浏览器的支持,但在较旧的浏览器或特定配置中可能存在限制。SSE 不需要额外的浏览器插件或库来实现基本功能。
- 双向通信:WebSocket 支持全双工通信,允许客户端和服务器通过单个连接互相发送数据。这使得实时双向通信成为可能。
- 任意数据格式:WebSocket 具有灵活的数据格式,支持任意的二进制或基于文本的数据传输。它们不像 SSE 那样强制使用特定的事件流格式。
- WebSocket 协议:WebSocket 使用建立在 TCP 之上的专门 WebSocket 协议。它提供了一个持久的、低延迟的双向通信通道。
- 浏览器兼容性:WebSocket 得到了大多数现代 Web 浏览器的支持,但在较旧的浏览器或特定配置中可能存在限制。WebSocket 功能需要原生 WebSocket 支持或使用 WebSocket 库或框架。
SSE 适用于服务器需要定期向客户端推送更新或事件的场景,例如实时通知、实时更新或数据流馈送。WebSocket 则适用于需要双向、互动和实时通信的应用程序,如聊天应用程序、多人游戏或协作编辑工具。
在选择使用 SSE 还是 WebSocket 时,应根据应用的具体需求进行决定。SSE 实现起来更简单,并且在浏览器中有更广泛的支持,而 WebSocket 则提供了更高级的功能和双向通信能力。
推送与拉取查询
同步查询类似于拉取查询,而异步查询对应于推送查询。这一点现在了解清楚很重要,因为在第 4 章讨论物化视图时这一点将变得更加明显。
在推送查询中,数据在数据库发生变化时会主动推送给客户端或应用程序。这允许实时更新和即时访问新信息,而无需持续轮询或手动请求。
由于数据在可用时立即推送,因此推送查询可以比拉取查询提供更低的延迟。无需等待客户端请求数据,它会主动提供。
推送查询与事件驱动架构很好地契合。它们使系统能够对事件做出反应,并根据收到的数据触发操作,从而提供更具响应性和事件导向的方法。
另一方面,拉取查询提供了更多的灵活性,因为它们允许客户端或应用程序在需要时随时获取数据。数据在请求时被获取,这使得数据检索的时间和频率更加可控。
拉取查询有助于减少不必要的网络流量,因为客户端只在必要时检索数据。在网络带宽有限或数据不经常变化的情况下,这可能是有利的。
拉取查询可以更高效地利用资源,因为服务器不需要主动向所有客户端或应用程序推送数据。这消除了连续监控和推送数据的需求,从而减少了服务器负载和资源消耗。另一方面,频繁的拉取查询可能导致非常高的资源消耗,因为数据存储可能需要过于频繁地扫描大量数据。
选择推送查询还是拉取查询取决于具体需求和使用场景。当实时更新和即时数据可用性至关重要时,通常会优先选择推送查询,而在数据检索可以按需进行且不太频繁时,拉取查询提供了更多的灵活性和效率。
但如果我们能同时利用推送和拉取查询的优势呢?使用拉取和推送查询的组合可以如下进行:
- 客户端提交查询作为拉取查询以获取 OLAP 系统中表的当前状态。
- 然后客户端订阅表中的更改,也就是只更新已更改的记录。
就像 OLTP 数据库中的 WAL 一样,客户端可以首先调用拉取查询来获取数据的快照,然后订阅表的 WAL 以获取增量更改。这一想法在图 3-6 中有所描述,在我们开始讨论第 5 章中的流数据库时,这一点将变得非常重要。
不幸的是,OLAP 数据存储不支持异步推送查询。OLAP 数据存储通常是终点,很难从中提取原始值。它们被优化用于提供分析结果,这些结果通常是数据的聚合或摘要。
总结
在本章中,我们介绍了 OLAP 数据存储,并将其与 OLTP 数据库进行了比较。我们还讨论了 OLAP 数据存储的许多优化技术,这些技术用于以低延迟提供分析查询。两个最重要的概念是:
- 状态感知摄取转换的重要性,以及它们如何为优化的分析查询准备数据。
- 推送和拉取查询以及它们提供分析数据的不同方式。
在第 4 章中,这些概念将非常重要,因为我们将详细探讨物化视图的概念。
转载自:https://juejin.cn/post/7402534719776342057