Real-Time End-to-End Integration with Apache Kafka in Apache Spark’s Structured Streaming

博客原文:
https://databricks.com/blog/2017/04/04/real-time-end-to-end-integration-with-apache-kafka-in-apache-sparks-structured-streaming.html

博客作者:Sunil Sitaula


结构化流 API可以以一致,容错的方式构建称为连续应用的端到端流应用,可以处理编写此类应用的所有复杂性。 这样做无需考虑流本身的实质性细节,也不需要通过在 Spark SQL中使用熟悉的概念(例如 DataFrameDataset)来进行。所有这些都引起了对想要利用它的用例的高度兴趣。 从 介绍ETL,再到 复杂的数据格式,该主题已经涉及广泛。 结构化流还与Kafka,HDFS,S3,RDBMS等第三方组件集成。

在本博客中,我将介绍与Kafka的端到端集成,使用它的消息,执行简单到复杂的窗口ETL,并将所需的输出推送到各种接收器,如内存、控制台、文件、数据库,然后返回Kafka本身。在写到文件的情况下,我还将讨论在现有分区表下写入新数据。

Connecting to a Kafka Topic

假设您有一个可以连接的Kafka集群,并且希望使用Spark的结构化流来提取和处理来自主题的消息。Databricks平台已经包含了一个用于结构化流的Apache Kafka 0.10连接器,因此很容易设置一个流来读取消息。

在读取流数据时可以指定许多选项。这些选项的详细信息可以在这里找到。

让我们快速看看上面设置的streamingInputDF DataFrame的模式。

它包括键、值、主题、分区、偏移量、时间戳和时间戳类型字段。我们可以根据处理的需要来挑选。字段是实际数据,而时间戳是消息到达时间戳。在窗口情况下,我们不应该将这个时间戳与可能包含在消息本身中的内容相混淆,后者在大多数情况下更相关。

Streaming ETL

现在已经设置了流,我们可以开始对其进行必要的ETL提取有意义的见解。 注意streamingInputDF是一个DataFrame。 由于DataFrame本质上是行的无类型数据集,因此我们可以对其执行类似的操作。

假设一般ISP匹配的JSON数据已推送到上面的Kafka的 <topic>。 一个示例值如下所示:

现在可以快速进行有趣的分析,比如有多少用户来自邮政编码,用户来自什么ISP等等。然后,我们可以创建仪表板,供组织的其他成员共享。让我们开始吧:

注意,在上面的命令中,当我们从Kafka主题中读取数据时,我们能够实时解析出传入的JSON消息中的邮政编码,对其进行分组并进行计数。 有了计数后,我们可以显示它,这将在后台触发流作业,并在新消息到达时不断更新计数。 现在,可以在Databricks中与我们组织的其余部分共享此自动更新的图表,作为访问控制的仪表板。

Windowing

现在我们已经连续执行了解析、选择、分组和计数查询,如果我们想在10分钟的窗口间隔内找出每个邮政编码的流量,滑动持续时间为5分钟,从1小时后2分钟开始,该怎么办?

在这种情况下,传入的JSON在 hittime 中包含时间戳记,因此让我们使用它来查询每10分钟窗口的点击量。

注意,在结构化流中,窗口化被视为groupBy操作。 下面的饼图代表每10分钟的窗口。

Output Options

到目前为止,我们已经看到最终结果会自动显示。 如果我们希望对输出选项进行更多控制,则可以使用多种输出模式。 例如,如果需要调试,则可能希望选择控制台输出。 如果我们需要能够在消耗数据时以交互方式查询数据集,那么内存输出将是理想的选择。 同样,输出可以写到文件、外部数据库,甚至可以流回Kafka。

让我们详细讨论一下这些选项。

Memory

在这个场景中,数据以内存表的形式存储。从这里,用户可以使用SQL查询数据集。表的名称是通过queryName选项指定的。注意,我们继续使用上面窗口例子中的streamingSelectDF

从这里开始,您现在可以进行更有趣的分析,就像在数据自动更新时对常规表所做的那样。

Console

在这种情况下,输出将打印到控制台/或者stdout日志。

File

这种情况对于长期的输出持久性来说是理想的。 与内存和控制台接收器不同,文件和目录是容错的。 因此,此选项需要一个检查点目录,该目录将维护状态以实现容错功能。

一旦数据被保存,就可以像在Spark中查询任何其他数据集一样查询它。

文件输出接收器的另一个优点是,您可以按列的任何变体对输入的消息进行动态分区。 在此特定示例中,我们可以按“zip”“day”进行分区。 这可以帮助提高查询速度,因为仅通过引用各个分区就可以跳过数据块。

然后我们可以按“day”“zip”对输入的数据进行分区。

让我们看看输出目录。

现在,分区数据可以直接在datasets和DataFrames中使用,如果创建了一个指向文件写入目录的表,可以使用Spark SQL来查询数据。

这种方法的一个警告是,必须向表中添加一个分区,才能访问它下面的数据集。

可以预先填充分区引用,以便在其中创建文件;它们会立即可用。

您现在可以对在将数据持久化到正确分区时自动更新的表执行分析。

Databases

通常,我们希望能够将流的输出写入外部数据库(例如MySQL)。 在撰写本文时,结构化流API不支持将外部数据库作为接收器。 但是,这样做的话,API选项将像.format(“ jdbc”).start(“ jdbc:mysql / ..”)一样简单。 同时,我们可以使用foreach接收器来完成此任务。 让我们创建一个自定义JDBC 接收器,它扩展了ForeachWriter并实现了其方法。

现在我们可以使用JDBCSink:

批处理完成后,可以根据需要将zip计数插入或追加到MySQL中。

Kafka

与写入数据库类似,当前的结构化流API不支持“ kafka”格式,但将在下一版本中提供。 同时,我们可以创建一个名为KafkaSink的自定义类,该类扩展了_ForeachWriter。 让我们看看它的外观:

现在我们可以使用writer了:

您现在可以看到,我们正在将消息发送回Kafka主题<topic2>。在本例中,我们正在推动更新的zipcode:count在每个批的末尾。另一件需要注意的事情是,流仪表板提供了关于传入消息与处理速度、批处理持续时间和用于生成消息的原始数据的分析。这在调试问题和监视系统时非常方便。

在Kafka的消费者方面,我们可以看到:

在本例中,我们以更新(updated)输出模式运行。当消息被消费时,在该批处理期间更新的邮政编码将被回推到Kafka。没有得到更新的邮政编码不会被发送。您还可以在完整(complete)模式下运行,就像我们在上面的数据库接收器中所做的那样,在这种模式中,所有带有最新计数的邮政编码都将被发送,即使有些邮政编码计数自上一个批处理以来没有变化。

Conclusion

在高层次上,我介绍了与Kafka的结构化流集成。此外,我还演示了如何使用api使用各种汇和源。需要注意的一点是,我们在这里讨论的内容与其他流同样相关:套接字、目录等。例如,如果希望使用套接字源并将处理过的消息推到MySQL,这里的示例应该能够通过更改流来实现这一点。同样,示例显示ForeachWriter可用于向多个下游系统展开写操作。我计划在以后的文章中更深入地展开见解以及此处涵盖的接收器。

我们在本博客中使用的示例代码可作为Databricks Notebook使用。 立即注册免费的Databricks社区版帐户,即可开始尝试使用结构化流式传输。 如果您有任何疑问,或者想开始使用Databricks,请与我们联系

最后,我鼓励您阅读我们有关结构化流的系列博客:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值