📜  如何为稳健的流处理开发标准 SQL 套件?

📅  最后修改于: 2021-09-09 12:00:44             🧑  作者: Mango

在当前数字化时代,企业需要实时数据分析和管理以保持领先地位。 SQL 一直是此类数据流分析和管理的前沿。然而,它有一些限制,这限制了流处理。

企业使用表和流的组合以及历史数据来对多个应用程序(如决策制定和其他业务操作)进行数据分析。尽管出现了数据分析和人工智能,但 SQL 仍然是用于数据流处理的主要查询语言之一。

因此,在这里我们将使用三种不同的方法来通过以下方式以更高的效率实现 SQL 的流式处理:

  • 时变关系
  • 事件时间语义
  • 物化控制

但是,在我们利用这些方法之前,让我们先了解一下当前的 SQL 方法:

  • 阿帕奇火花:
    这个声明式 API 建立在 Spark SQL 的执行引擎和优化器之上,实际上是一个 Spark 的数据集 API。通常,数据集程序是在有限数据流上执行的。 Dataset API 的流媒体通常称为Structured Streaming 。结构化流查询通过微批处理执行引擎进行评估,该引擎以小批量处理数据流并找到容错保证。
  • KSQL:
    它建立在Kafka流之上,Kafka流是Apache Kafka项目下开发的流处理框架。 KSQL 是一个声明性包装器,它涵盖了 Kafka 流并开发了自定义的 SQL 类型语法来声明流和表。它更侧重于物化视图语义。
  • 阿帕奇弗林克:
    它由两个关系 API 组成——LINQ 样式表 API 和 SQL。它使用通用逻辑计划表示和优化的 Apache calcite 来查询来自两个关系 API 的查询。然后执行作为批处理或流处理进行。
  • 阿帕奇梁:
    它是专门开发的,牢记光束对有界和无界数据处理的统一优化。它使用语义的子集来执行数据流。
  • 阿帕奇方解石:
    它是 Flink SQL 和 Beam SQL 中流行的流式 SQL 解析器。它解析、优化和支持流处理语义。

    现在,让我们了解三种流式 SQL 的新方法。

  • 时变关系:
    这种方法论侧重于“时间”元素。每当我们处理流关系时,我们都需要考虑随时间变化的相对时间关系。对于这个问题,我们可以使用时变关系(TVR),它是一种关系,其内容随时间而变化。

    TVR 可以通过多种方式编码或具体化,尤其是作为一系列经典关系或作为“插入”和“删除”操作的序列。这两种编码互为对偶,对应于表和流。虽然编码的二元性可能是一个问题,但我们打算将其用作优势。

    我们可以利用流和表都是公共语义对象的表示这一事实。虽然我们可以统一对待 TVR,但利用流本身的变化,TVR 可以优化和具体化流,以获得更好的查询结果。

  • 事件时间语义:
    在许多情况下,假设数据是根据事件时间确定的,但这不适用于移动应用程序开发、分布式系统或分片存档数据。通常,数据根据事件的时间进行了精简,而执行逻辑的进度却不一致。

    这是因为一小时的处理时间与一小时的事件时间无关。因此,必须考虑事件时间才能获得正确的结果。 STREAM 系统会考虑事件时间,并包含一个称为心跳的功能,该功能可缓冲不按事件时间顺序排列的数据,并将其送入查询处理器。这通过引入延迟来允许时间戳偏差。而 Millwheel 系统使用水印——它可以计算出与元数据一起乱序的数据。

    但是,最佳实践是时间戳和水印的组合,因为它们一起可以允许正确计算事件时间。这些计算是通过对时间间隔进行分组并在没有无限资源的情况下执行它们来执行的。

  • 物化控制:
    这种方法可以控制在具体化行时如何呈现关系。在第一种方法中,我们可以使用流更改日志来捕获两个关系版本之间的元素到元素的差异,并进一步使用 INSERT 和 DELETE 的编码序列来改变 TVR。

    另一种方法是物化延迟 ——这种方法是通过将表和流建模为 TVR 来使用的,所获得的结果关系是 TVR。

基于NEXmark 基准的数据流查询示例:

在查询以每 10 分钟的时间相关结果监控当前拍卖的最高价格项目的情况下,它得出具有最高出价的结果。

CQL 中的查询:

SELECT
     Rstream ( B . price, B . itemid )
FROM
     Bid [ RANGE 10 MINUTE SLIDE 10 MINUTE ] B
WHERE
B . price =
       ( SELECT MAX ( B1 . price ) FROM BID
       [ RANGE 10 MINUTE SLIDE 10 MINUTE ] B1 );

SQL 中的查询:

SELECT
MaxBid . wstart, MaxBid . wend,
Bid . bidtime, Bid . price, Bid . itemid
FROM
Bid,
( SELECT
     MAX ( TumbleBid . price ) maxPrice,
     TumbleBid . wstart wstart,
     TumbleBid . wend wend
FROM
     Tumble (
         data = > TABLE ( Bid ),
         timecol = > DESCRIPTOR ( bidtime )
         dur = > INTERVAL '10 ' MINUTE ) TumbleBid
 GROUP BY
     TumbleBid . wend ) MaxBid
  
WHERE
     Bid . price = MaxBid . maxPrice AND
     Bid . bidtime >= MaxBid . wend
                  - INTERVAL '10 ' MINUTE AND
     Bid . bidtime < MaxBid . wend ;

要点:
相反与以前的方法,这种方法使用时间戳作为投标流中明确的数据和行不会出现在bidtime的顺序。翻转是用含有10 bidtime分钟的间隔每个出价流分配TVR。

通过上面的例子,我们可以看到,随着投标关系随着时间的推移而演变,随着时间的推移添加新元素,查询定义的关系也随之演变。因此,我们可以使用上述方法并引入可以随着查询元素的变化而演变的 TVR。