linux 如何查询db2状态_FlinkSQL用于强大数据流和静态数据查询、如何限制状态的生命周期...

本文介绍了Flink SQL如何用于强大的数据流和静态数据查询,强调了其作为批处理和流处理统一API的特性。通过实例展示了如何使用Flink SQL进行数据转换和窗口化聚合,探讨了状态TTL在限制状态生命周期中的作用,确保数据合规性和存储效率。
摘要由CSDN通过智能技术生成

FlinkSQL用于强大数据流和静态数据查询

虽然Flink SQL最初于2016年8月与Flink 1.1.0一起发布,但最近的Flink版本增加了相当多的功能,通过消除编写Java / Scala代码的需要,使Flink SQL更易于使用。在这篇文章中,我们希望(重新)从这些变化所带来的新角度介绍Flink SQL,同时为经验丰富的用户提供一些额外的知识。新添加的SQL命令行(SQL CLI)可以轻松快速浏览流中的数据或静态数据(例如,在数据库或HDFS中)。它还可用于构建功能强大的数据转换管道或分析管道。在这篇文章中,我们想要探索当前可用的功能,而后续帖子将更详细地介绍特定功能,并介绍Flink 1.7即将推出的令人兴奋的新功能,例如使用MATCH_RECOGNIZE扩展的复杂事件处理和改进基于时间的浓缩加入。

e7280d60e16aaffbd2be6b3b94c6a4b6.png

flink SQL在我们深入研究一些动手实例之前,我们列出了Flink SQL的一些亮点:

  • Flink SQL是批处理和流处理的统一API:这允许使用相同的查询来处理历史数据和实时数据
  • 支持处理时间和事件时间语义
  • 支持使用嵌套的Avro和JSON数据
  • 用户定义的标量,聚合和表值函数
  • 无需编码的SQL命令行(即没有Java / Scala编码)
  • 支持各种类型的流连接(保持眼睛去除后续帖子)
  • 支持聚合,包括窗口和没有窗口对于本文的其余部分,我们将使用由Fabian Hueske和Timo Walther在Dawid Wysakowicz的帮助下创建的奇妙的ApacheFlink®SQL培训启发的示例。我们还提供了一个更新的基于docker-compose的演示设置,您可以使用它来跟随示例:https://github.com/aljoscha/sql-demo

与外部世界交谈,又名来源和汇

使用Flink SQL的命令行客户端时,我们要做的第一件事就是定义源和接收器。否则,我们将无法读取或写入任何数据。源和接收器在YAML配置文件中定义,以及其他配置设置。YAML文件中的源和接收器配置类似于SQL DDL语句(Flink社区目前正在讨论对SQL DDL的支持)。对于我们正在进行的示例,我们假设我们有一个Kafka主题,其中存储了我们想要进一步处理和分析的出租车游乐设施的信息。它的配置如下所示:

tables:- name: TaxiRidestype: sourceupdate-mode: appendschema:- name: rideIdtype: LONG- name: rowTimetype: TIMESTAMProwtime:timestamps:type: "from-field"from: "rideTime"watermarks:type: "periodic-bounded"delay: "60000"- name: isStarttype: BOOLEAN- name: lontype: FLOAT- name: lattype: FLOAT- name: taxiIdtype: LONG- name: driverIdtype: LONG- name: psgCnttype: INTconnector:property-version: 1type: kafkaversion: 0.11topic: TaxiRidesstartup-mode: earliest-offsetproperties:- key: zookeeper.connectvalue: zookeeper:2181- key: bootstrap.serversvalue: kafka:9092- key: group.idvalue: testGroupformat:property-version: 1type: jsonschema: "ROW(rideId LONG, isStart BOOLEAN, rideTime TIMESTAMP, lon FLOAT, lat FLOAT, psgCnt INT, taxiId LONG, driverId LONG)"

在Flink SQL中,源,接收器以及介于两者之间的所有内容称为表。在这里,我们基于包含JSON格式的事件的Kafka主题定义初始表。我们定义Kafka配置设置,格式以及我们如何将其映射到模式,以及我们希望如何从数据中导出水印。除了JSON之外,Flink SQL还内置了对CSV和Avro格式的支持,并且还可以使用自定义格式对其进行扩展。一个有趣的事实是Flink SQL始终支持在JSON和Avro架构中处理嵌套数据。现在我们讨论了源表的配置和格式,让我们打开SQL培训的Docker容器。

git clone https://github.com/aljoscha/sql-democd sql-demodocker-compose up -ddocker-compose exec sql-client ./sql-client.sh

Windows用户,请查看更详细的培训说明。从Flink SQL命令行客户端,我们可以列出我们定义的表:

Flink SQL> SHOW TABLES;AreaCnts_sinkTaxiRidesTenMinPsgCnts_sink

我们还可以检查任何表的模式:

Flink SQL> DESCRIBE TaxiRides;root|-- rideId: Long|-- rowTime: TimeIndicatorTypeInfo(rowtime)|-- isStart: Boolean|-- lon: Float|-- lat: Float|-- taxiId: Long|-- driverId: Long|-- psgCnt: Integer

有了这个,让我们看看我们可以用我们的表做什么。有关配置Flink SQL以及定义源,接收器及其格式的详细信息,请参阅文档。

按摩数据您可能想要做的最简单的事情之一是将数据格式化为正确的格式以便进一步处理。这可能包括:

  • 在模式之间转换,例如将JSON事件流转换为Avro编码
  • 用SQL术语删除字段或将其投影
  • 过滤掉我们不感兴趣的整个事件

让我们看一下从架构转换开始我们将如何做到这些。当我们想要从Kafka读取数据时,将数据转换为不同的格式,并将数据写回不同的Kafka主题以进行下游处理,我们所要做的就是定义源表(如上所述)然后定义作为接收器的表格具有不同的格式:

tables:- name: TaxiRides_Avrotype: sinkupdate-mode: appendschema:- name: rideIdtype: LONG- name: rowTimetype: TIMESTAMP- name: isStarttype: BOOLEAN- name: lontype: FLOAT- name: lattype: FLOAT- name: taxiIdtype: LONG- name: driverIdtype: LONG- name: psgCnttype: INTconnector:property-version: 1type: kafkaversion: 0.11topic: TaxiRides_Avroproperties:- key: zookeeper.connectvalue: zookeeper:2181- key: bootstrap.serversvalue: kafka:9092- key: group.idvalue: trainingGroupformat:property-version: 1type: avroavro-schema: >{"type": "record","name": "test","fields" : [{"name": "rideId", "type": "long"},{"name": "rowTime", "type": {"type": "long", "logicalType": "timestamp-millis"}},{"name": "isStart", "type": "boolean"},{"name": "lon", "type": "float"},{"name": "lat", "type": "float"},{"name": "taxiId", "type": "long"},{"name": "driverId", "type": "long"},{"name": "psgCnt", "type": "int"}]}

通过我们的源和接收器定义转换数据变得如此简单:

Flink SQL> INSERT INTO TaxiRides_Avro SELECT * FROM TaxiRides;[INFO] Submitting SQL update statement to the cluster...[INFO] Table update statement has been successfully submitted to the cluster:Cluster ID: StandaloneClusterIdJob ID: ffa9109b9cad077ec83137f55ec6d1c5Web interface: http://jobmanager:8081

我们的查询作为常设查询提交给Flink集群。您可以通过访问http:// localhost:8081来监视和控制来自Flink的WebUI的查询。我们可以通过引入投影和过滤来构建这个简单的模式。如果我们只想在结果中包含某些字段,我们可以在SELECT查询中指定。例如:

Flink SQL> INSERT INTO TaxiRides_Avro SELECT rideIdId, taxiId, driverId FROM TaxiRides;

这只会给我们事件中的ID。(请记住,接收器的格式需要适应此查询才能工作。)基于此,我们可以做的另一件简单事情就是过滤掉整个事件。考虑一下我们只对在纽约发生的出租车乘坐感兴趣的情况。事件具有lon和lat分别给出事件发生的经度和纬度的字段。我们可以使用它们来确定事件是否发生在纽约:

Flink SQL> SELECT * FROM TaxiRides WHERE isInNYC(lon, lat);

你会发现一件有趣的事情,那就是isInNYC()。这是我们在SQL客户端配置中定义的用户定义函数或UDF。我们可以通过以下方式查看我们提供的用户功能:

Flink SQL> SHOW FUNCTIONS;timeDifftoCoordsisInNYCtoAreaId

就像在Flink SQL客户端配置文件中配置的其他内容一样:

functions:- name: timeDifffrom: classclass: com.dataartisans.udfs.TimeDiff- name: isInNYCfrom: classclass: com.dataartisans.udfs.IsInNYC- name: toAreaIdfrom: classclass: com.dataartisans.udfs.ToAreaId- name: toCoordsfrom: classclass: com.dataartisans.udfs.ToCoords

UDF是实现特定接口并在客户端注册的Java类。有不同类型的用户功能:标量函数,表函数和聚合函数。请继续关注后续博客文章,其中详细介绍了用户定义的函数,但您也可以立即查看UDF文档。

使用Flink SQL中的视图构建查询

一旦我们有足够复杂的SQL查询,它们就会变得有点难以理解。我们可以通过在Flink SQL中定义视图来缓解这种情况。这类似于您在编程语言中定义变量以给出某个名称的方式,以便您以后能够重用它。假设我们想要在早期的例子的基础上进行构建,并创建一个在给定日期之后在纽约发生的游乐设施的视图。我们会这样做:

Flink SQL> CREATE VIEW TaxiRides_NYC AS SELECT * FROM TaxiRidesWHERE isInNYC(lon, lat)AND rowTime >= TIMESTAMP '2013-01-01 00:00:00';[INFO] View has been created.

我们可以通过以下方式找出我们可以获得的观点:

Flink SQL> SHOW TABLES;TaxiRidesTaxiRides_AvroTaxiRides_NYC

需要注意的一点是,创建视图实际上并不实例化任何常设查询或产生任何输出或中间结果。视图只是可以重用的查询的逻辑名称,并允许更好地构建查询。这与其他一些类似SQL的流式系统不同,在这些系统中,每个中间查询都会创建数据并吞噬资源。视图是Flink 1.7的即将推出的功能,但它已经实现并合并到主分支中,这就是为什么我们已经在这里提到它。另外,它非常有用。

具有事件时间支持的窗口化聚合

作为最后一步,我们希望展示一个更复杂的查询,它将我们到目前为止所解释的内容汇集在一起。考虑一种情况,我们希望监控正在发生的游乐设施,并且需要知道纽约某个特定区域的游乐设施数量何时超过阈值(比如说5)。这是这样做的查询:

SELECTtoAreaId(lon, lat) AS area,TUMBLE_END(rowTime, INTERVAL '5' MINUTE) AS t,COUNT(*) AS cFROM TaxiRides_NYCWHERE isStart = TRUEGROUP BYtoAreaId(lon, lat),TUMBLE(rowTime, INTERVAL '5' MINUTE)HAVING COUNT(*) >= 5;

在上面的示例中,我们执行以下操作:

  1. 我们使用之前创建的视图,其中包含在特定日期之后发生的纽约事件,
  2. 我们过滤掉那些不是“开始事件”的事件,
  3. 我们使用另一个用户定义的函数将对转换为lon, lat区域id和group by,
  4. 我们指定我们想要有五分钟的窗口,最后
  5. 我们过滤掉那些计数小于5的窗口。

在现实世界的用例中,我们现在将其写入Elasticsearch接收器并使用它为仪表板或通知系统供电。这留给读者练习。(提示:Apache Flink SQL培训确实在后面的练习中详细介绍了这一点。)

结论

在这篇博文中,我们解释了如何在不编写Java代码的情况下使用Flink SQL实现简单的数据转换和数据按摩作业。我们还解释了如何使用视图来构建更复杂的查询并使其易于理解。最后,我们开发了一个更复杂的查询,它结合了用户定义的函数,窗口聚合和事件时间支持。在后续帖子中,我们将提供有关如何开发和使用用户定义函数的更多见解,我们将深入了解Flink SQL的强大连接以及如何使用它们来丰富数据。在Flink 1.7.0发布之后安排的未来帖子将为使用Flink SQL的数据丰富,复杂事件处理和模式检测引入强大的新增功能。

Apache Flink的状态TTL:如何限制状态的生命周期

许多有状态流应用程序的一个常见要求是能够控制应用程序状态的访问时间(例如,由于GDPR等法律规定)以及何时丢弃它。此博客文章介绍了使用1.6.0版本添加到Apache Flink的状态生存时间(TTL)功能。

我们概述了动机并讨论了新的状态TTL功能的用例。此外,我们将展示如何使用和配置它,并解释Flink如何使用TTL内部管理状态。博客文章最后总结了未来的改进和扩展。

d4c2b81468a854fc1acd894a9292fece.png

使用Apache Flink介绍有状态流处理

任何非平凡的实时流应用程序都包括有状态操作。Apache Flink为容错状态流处理提供了许多强大的功能。用户可以选择维护状态的不同状态原语(原子值,列表,映射)和后端(堆内存,RocksDB)。处理函数中的应用程序逻辑可以访问和修改状态。通常,状态与密钥相关联,允许类似于密钥/值存储的可伸缩处理和存储。Apache Flink透明地管理状态分布(包括对扩展或扩展的支持),并定期执行检查点,以便在出现故障时恢复作业,具有一次性状态一致性保证。

在本博文的其余部分中,我们使用有状态应用程序的示例,该应用程序为每个用户在上次登录时提取用户登录事件和存储流,以改善频繁访问者的体验。

国家的暂时性

国家只应在有限的时间内维持有两个主要原因。

  • 遵守数据保护法规

围绕数据隐私法规的最新发展,例如欧盟引入的新的通用数据保护法规(GDPR),使得遵守这些数据要求成为IT行业的一个重要主题。特别是对于在有限时间内保留数据并且此后阻止访问数据的要求对于向其客户提供短期服务并处理其个人数据的公司来说是一个共同的挑战。在我们存储上次登录时间的应用程序中,永久保留信息以防止对用户隐私的不必要洞察是不可接受的。因此,应用程序需要在一段时间后删除信息。

  • 更有效地管理状态存储的大小

另一个问题是国家存储的规模不断扩大。通常,数据需要暂时保留,同时围绕它进行一些用户活动,例如Web会话。当活动结束时,不再对该数据感兴趣,同时它仍占用存储空间。应用程序必须采取额外操作并明确删除无用状态以清理存储。按照我们之前存储上次登录时间的示例,经过一段时间后可能没有必要,因为稍后可以将用户视为“不经常”。

这两个要求都可以通过一个功能来解决,该功能一旦不再被访问或者一旦没有足够的价值将密钥保存在存储中,就会“神奇地”删除密钥的状态。

我们对于它可以做些什么呢?

Apache Flink的1.6.0版本引入了State TTL功能。流处理应用程序的开发人员可以将运营商的状态配置为在特定时间段(生存时间)内未被触及的情况。过期的状态后来被懒惰的清理策略垃圾收集。

在Flink的DataStream API中,应用程序状态由状态描述符定义。通过将StateTtlConfiguration传递给状态描述符来配置状态TTL。以下Java示例 演示如何创建状态TTL配置并将其提供给状态描述符,该状态描述符将用户的上次登录时间保存为Long值:

import org.apache.flink.api.common.state.StateTtlConfig;import org.apache.flink.api.common.time.Time;import org.apache.flink.api.common.state.ValueStateDescriptor;StateTtlConfig ttlConfig = StateTtlConfig   .newBuilder(Time.days(7     新))   .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)   .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)   .build();ValueStateDescriptor lastUserLogin = ValueStateDescriptor<>("lastUserLogin", Long.class);lastUserLogin.enableTimeToLive(ttlConfig);

Flink提供了多个选项来配置状态TTL功能的行为。

  1. 什么时候重置? 默认情况下,状态修改时更新状态条目的到期时间。可选地,它还可以在读访问时更新,代价是额外的写操作以更新时间戳。
  2. 哪个时间语义用于生存时间计时器? 使用Flink 1.6.0,用户只能根据处理时间定义状态TTL。计划在未来的Apache Flink版本中支持事件时间。
  3. 可以最后一次访问过期状态吗? 让我们假设一些状态已经过期,但它仍然可以在存储中使用,但尚未被删除。如果正在读取此状态,则用户可以为其值设置不同的可见性类型。在这两种情况下,该州随后被移除。
  4. 第一种选择是永远不会返回过期状态。这样,状态对用户是隐藏的,并且不再存在,这阻止了在所需的时间段之后访问任何个人数据。
  5. 第二个可用选项是返回已过期但尚未垃圾收集的状态。此替代方案解决了最终存储清理很重要但应用程序可以使用仍然可用但已过期状态的应用程序。您可以在Apache Flink文档中阅读有关如何使用状态TTL的更多信息。

在内部,状态TTL功能是通过在这种情况下存储最后修改的附加时间戳以及用户值来实现的。虽然这种方法增加了一些存储开销,但它允许Flink在状态访问,检查点,恢复或专用存储清理过程中检查过期状态。

"取出垃圾”

在读取操作中访问状态对象时,Flink将检查其时间戳并清除状态是否已过期(取决于配置的状态可见性,是否返回过期状态)。由于这种延迟删除,永远不会再次访问的过期状态将永远占用存储空间,除非它是垃圾回收。

那么如何在没有应用程序逻辑明确处理它的情况下删除过期状态呢?通常,有不同的可能策略在后台删除它。

仅当获取检查点或保存点的完整快照时,Flink 1.6.0才支持自动驱逐过期状态。请注意,状态逐出不适用于增量检查点。必须明确启用完整快照的状态驱逐,如以下示例所示:

StateTtlConfig ttlConfig = StateTtlConfig   .newBuilder(Time.days(7))本地存储暂时不受影响,但存储快照的大小减小了。当操作员从快照重新加载其状态时,即在恢复或从保存点开始时,仅清理操作员的本地状态。将来,可以改进此清理策略,以将状态删除异步传播到正在运行的本地存储。   .cleanupFullSnapshot()   .build();

由于这些限制,应用程序仍然需要在Flink 1.6.0中过期后主动删除状态。一种常见的方法是基于定时器在一定时间后手动清理状态。我们的想法是使用TTL每状态值和访问来注册一个计时器。当计时器过去时,如果自定时器注册后没有发生其他状态访问,则可以清除状态。这种方法引入了额外的成本,因为定时器消耗存储以及原始状态。但是,Flink 1.6为计时器处理添加了重大改进,例如高效的计时器删除(FLINK-9423) 和支持RocksDB的计时器服务。

Apache Flink的开源社区目前正在为过期状态开发额外的垃圾收集策略。不同的想法仍处于进行中的工作模式,并计划用于未来版本。

一种方法基于Flink计时器,其工作方式与上述手动清理类似。但是,用户不需要自己实现清理逻辑,并且状态会自动清除。

更复杂的想法取决于特定状态后端的特征,包括: 在状态访问或记录处理时触发的堆后端中的增量部分清理。 RocksDB特定的过滤器,用于在常规压缩过程中过滤掉过期的值。

我们鼓励您加入对话并在Apache Flink JIRA板上分享您的想法和想法,或者订阅下面的Apache Flink邮件列表。

摘要

基于时间的状态访问限制和自动状态清理是有状态流处理领域的常见挑战。凭借其1.6.0版本,Apache Flink引入了第一个实现状态TTL支持以解决这些问题。在当前版本中,状态TTL在配置的超时后保证状态不可访问,以符合GDPR或任何其他数据合规性规则。Flink社区正在开展若干扩展,以在未来版本中改进和扩展State TTL功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值