审校 | 重楼
实时流架构旨在连续地摄入、处理和分析数据,从而实现近乎实时的决策和见解。它们需要具有低延迟,处理高吞吐量数据量,并且在发生故障时具有容错的能力。具备这些能力面临的一些挑战包括:
- 摄入——以高吞吐量从各种数据源、格式和结构中摄入数据,即使在大量数据流爆发期间也是如此。
- 处理——在确保有状态计算、无序事件和数据延迟到达等复杂情况得到处理的同时,以可扩展和容错的方式确保恰好一次(Exactly-once)的处理语义。
- 实时分析——在不影响数据完整性或一致性的情况下,对从数据流源头不断摄入和处理的新数据实现低延迟的查询响应。
独立的技术组件很难满足所有的需求,这就是实时流架构由多个协同工作的专用工具组成的原因。
一、Apache的Kafka、Flink、Pinot介绍
以下深入了解实时流架构的核心技术——Apache Kafka、Apache Flink和Apache Pinot。
1.Apache Kafka
Apache Kafka是一个分布式流处理平台,是实时数据管道的中枢神经系统。Apache Kafka的核心是围绕发布-订阅架构构建的,生产者将记录发布到主题,消费者订阅这些主题来处理记录。
Apache Kafka架构的关键组件包括:
- 代理是存储数据和服务客户端的服务器。
- 主题是记录发送到的类别。
- 分区是并行处理和负载平衡的主题划分。
- 消费者群体使多个消费者能够有效地协调和处理记录。
Kafka是各行业实时数据处理和事件流的理想选择,其主要功能包括:
- 高吞吐量
- 低延迟
- 容错性
- 耐用性
- 横向可扩展性
2.Apache Flink
Apache Flink是一个开源流处理框架,旨在对无界和有界数据流执行有状态计算。它的架构围绕分布式数据流引擎,确保应用程序的高效和容错执行。
Apache Flink的主要功能包括:
- 支持流和批处理
- 通过状态快照和恢复进行容错
- 事件时间处理
- 高级窗口功能
Apache Flink集成了各种各样数据的源和汇——源是Apache Flink处理的输入数据流,而汇是Apache Flink输出处理过的数据的目的地。支持的Apache Flink源包括消息代理(例如Apache Kafka)、分布式文件系统(例如HDFS和S3)、数据库和其他流数据系统。类似地,Apache Flink可以将数据输出到各种各样的接收器,包括关系数据库、NoSQL数据库和数据湖。
3.Apache Pinot
Apache Pinot是一个实时分布式在线分析处理(OLAP)数据存储,专为大规模数据流的低延迟分析而设计。Apache Pinot的架构旨在有效地处理批处理数据和流数据,提供即时查询响应。Apache Pinot擅长对从Kafka等数据流来源获取的快速变化的数据进行分析查询。它支持多种数据格式,包括JSON、Avro和Parquet,并通过其分布式查询引擎提供类似SQL的查询功能。Pinot的星树索引支持快速聚合、高效过滤、高维数据和压缩。
二、Apache 的Kafka、Flink和Pinot集成
以下介绍Apache的Kafka、Flink和Pinot如何协同工作,对流数据进行实时洞察、复杂事件处理和低延迟分析查询的概述:
(1)Kafka作为一个分布式流媒体平台,从各种来源实时摄取数据。它为流数据提供持久、容错和可扩展的消息队列。
(2)Flink从Kafka主题中消耗数据流。它对传入的数据执行实时流处理、转换和计算。Flink强大的流处理功能支持复杂的操作,例如窗口聚合、有状态计算和基于事件时间的处理。然后将Flink的处理数据加载到Pinot中。
(3)Pinot摄入数据流,构建实时和离线数据集,并为低延迟分析查询创建索引。它支持一个类似SQL的查询接口,并且可以对实时和历史数据提供高吞吐量和低延迟的查询。
图1 Kafka、Flink和Pinot是实时流架构的组件
以下深入了解各个组件:
1.Kafka摄入
Kafka提供了几种摄入数据的方法,每种方法都有自己的优点。使用Kafka生产者客户端是最基本的方法。它提供了一种简单有效的方法,可以将记录从各种数据源发布到Kafka主题。开发人员可以通过将生产者客户端集成到Kafka客户端库支持的大多数编程语言(Java、Python等)的应用程序中来利用生产者客户端。
生产者客户端处理各种任务,包括通过跨分区分发消息来实现负载平衡。这通过等待Kafka代理的确认来确保消息的持久性,并管理失败发送尝试的重试。通过利用压缩、批处理大小和逗留时间等配置,Kafka生产者客户端可以针对高吞吐量和低延迟进行优化,使其成为Kafka实时数据摄取的高效可靠工具。
其他选择包括:
- Kafka Connect是一个可扩展和可靠的数据流工具,具有内置功能,例如偏移管理、数据转换和容错。它可以通过源连接器将数据读入Kafka,也可以通过连接器将数据从Kafka写入外部系统。
- Debezium在将数据摄入Kafka方面非常受欢迎,它使用源连接器来捕获数据库变更(插入、更新、删除)。它将这些变更发布到Kafka主题中,以实现数据库的实时更新。
Kafka生态系统也有一套丰富的第三方数据摄取工具。
2.Kafka-Flink集成
Flink提供了一个Kafka连接器,允许它在Kafka主题之间消费和生成数据流。
连接器是Flink分布的一部分,它提供了容错性和恰好一次的语义。
连接器由两部分组成:
- KafkaSource允许Flink使用来自一个或多个Kafka主题的数据流。
- KafkaSink允许Flink为一个或多个Kafka主题生成数据流。
以下是一个如何在Flink的数据流API中创建KafkaSource的例子:
Java
KafkaSource source = KafkaSource.builder()
.setBootstrapServers(brokers)
.setTopics("ad-events-topic")
.setGroupId("ad-events-app")
.setStartingOffsets(OffsetsInitializer.earliest())
.setValueOnlyDeserializer(new SimpleStringSchema())
.build();
DataStream stream = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");
需要注意的是,FlinkKafkaConsumer基于遗留的SourceFunction API,已经标记为弃用并已删除。新的基于数据源的API,包括KafkaSource,对水印生成、有界流(批处理)和动态Kafka主题分区的处理等方面提供了更大的控制。
3.Flink-Pinot集成
有几个选项可以将Flink与Pinot集成,将处理后的数据写入Pinot表。
选项1:从Flink到Kafka再到Pinot
这是一个两个步骤的过程,首先使用Flink Kafka连接器的KafkaSink组件将数据从Flink写入Kafka。以下是一个示例:
Java
DataStream stream = ;
KafkaSink sink = KafkaSink.builder()
.setBootstrapServers(brokers)
.setRecordSerializer(KafkaRecordSerializationSchema.builder()
.setTopic("ad-events-topic")
.setValueSerializationSchema(new SimpleStringSchema())
.build()
)
.setDeliveryGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
.build();
stream.sinkTo(sink);
作为第二个步骤的一部分,在Pinot端,需要为Kafka配置实时摄取支持,它将实时摄取数据到Pinot表中。
这种方法解耦了Flink和Pinot,允许独立扩展它们,并潜在地利用架构中其他基于Kafka的系统或应用程序。
选项2:从Flink到Pinot(直接)
另一种选择是使用作为Pinot发行版一部分的Flink SinkFunction。这种方法通过将流处理(或批处理)Flink应用程序直接写入指定的Pinot数据库来简化集成。这种方法简化了管道,因为它消除了中间步骤或额外组件的需要。它确保处理后的数据在Pinot中随时可用,以实现低延迟查询和分析。
三、优秀实践和注意事项
虽然在使用Kafka、Flink和Pinot进行实时流解决方案时需要考虑很多因素,但这里有一些常见的因素。
1.恰好一次(Exactly-once)
恰好一次语义保证即使在出现故障或无序交付的情况下,每条记录也只处理一次。实现这种行为需要流处理管道中涉及的组件之间的协调。
(1)使用Kafka的幂等设置来保证消息只传递一次。这包括在生产者上启用enable.idempotence设置,并在消费者上使用适当的隔离级别。
(2)Flink的检查点和偏移跟踪确保只有处理过的数据被持久化,从而允许从故障中进行一致的恢复。
(3)最后,Pinot的追加功能和唯一的记录标识符消除了摄入过程中的重复,保持了分析数据集中的数据完整性。
2.Kafka-Pinot直接集成vs.使用Flink
直接集成Kafka和Pinot还是使用Flink作为中间层取决于流处理需求。如果需求涉及最小的流处理、简单的数据转换或较低的操作复杂性,可以使用Kafka内置的支持将Kafka与Pinot直接集成,以从Kafka主题中消费数据并将其摄入实时表中。此外,可以在摄入过程中在Pinot中执行简单的转换或过滤,从而消除了对专用流处理引擎的需求。
如果用例需要复杂的流处理操作,例如窗口聚合、有状态计算、基于事件时间的处理或从多个数据源摄取,则建议使用Flink作为中间层。Flink提供强大的流处理API和操作符来处理复杂的场景,提供跨应用程序的可重用处理逻辑,并且可以在将流数据摄取到Pinot之前对流数据执行复杂的提取-转换-加载(ETL)操作。在具有复杂流需求的场景中,引入Flink作为中间流处理层可能是有益的,但它也增加了操作的复杂性。
3.可扩展性和性能
处理大量数据并确保实时响应需要仔细考虑整个管道的可扩展性和性能。讨论最多的两个方面包括:
(1)可以利用这三个组件固有的水平可扩展性。添加更多Kafka代理来处理数据摄取量,拥有多个Flink应用实例来并行处理任务,并扩展Pinot服务器节点来分配查询执行。
(2)可以基于常用查询过滤器对数据进行分区来有效地利用Kafka分区,从而提高Pinot中的查询性能。通过在工作节点之间均匀分布数据,分区也有利于Flink的并行处理。
4.常用用例
可能正在使用构建在实时流架构之上的解决方案,有些人甚至没有意识到这一点。以下将介绍几个常用示例。
(1)实时广告
现代广告平台需要做的不仅仅是提供广告,还必须处理广告拍卖、竞价和实时决策等复杂流程。一个值得注意的例子是Uber公司的UberEats应用程序,广告事件处理系统必须以最小的延迟发布结果,同时确保没有数据丢失或重复。为了满足这些需求,Uber公司使用Kafka、Flink和Pinot构建了一个系统来实时处理广告事件流。
该系统依赖于Flink作业通过Kafka主题进行通信,最终用户数据存储在Pinot(Apache Hive)中。通过结合Kafka和Flink提供的恰好一次语义、Pinot中的追加功能以及用于重复数据删除和幂等性的唯一记录标识符的组合来保持准确性。
(2)面向用户的分析
当涉及到延迟和吞吐量时,面向用户的分析有非常严格的要求。LinkedIn已经广泛采用Pinot来支持整个公司的各种实时分析用例。Pinot作为几个面向用户的产品特性的后端,包括“谁查看了我的个人资料”。Pinot支持对大量数据集的低延迟查询,允许LinkedIn为其成员提供高度个性化和最新的体验。除了面向用户的应用程序,Pinot还被用于LinkedIn的内部分析,并为各种内部仪表板和监控工具提供支持,使团队能够实时了解平台性能、用户参与度和其他运营指标。
(3)欺诈检测
对于欺诈检测和风险管理场景,Kafka可以摄入与交易数据、用户活动和设备信息相关的实时数据流。Flink的管道可以应用模式检测、异常检测、基于规则的欺诈检测和数据丰富等技术。Flink的有状态处理能力能够在数据流经管道时维护和更新用户或事务级状态。处理后的数据,包括标记的欺诈活动或风险评分,然后转发给Pinot。
风险管理团队和欺诈分析师可以在Pinot实时数据的基础上执行临时查询或构建交互式仪表板。这可以识别高风险用户或交易,分析欺诈活动的模式和趋势,监控实时欺诈指标和KPI,并调查标记为潜在欺诈的特定用户或交易的历史数据。
结论
Kafka的分布式流平台支持高吞吐量的数据摄取,而Flink的流处理能力允许复杂的转换和有状态的计算。最后,Pinot的实时OLAP数据存储促进了低延迟的分析查询,使组合解决方案成为需要实时决策和见解的用例的理想选择。
虽然Kafka、Flink和Pinot等单个组件非常强大,但在云计算和内部部署之间大规模管理它们在操作上可能很复杂。托管流媒体平台减少了操作开销,并抽象出许多低级集群配置、配置、监控和其他操作任务。它们允许根据不断变化的工作负载需求弹性地增加或减少资源配置。这些平台还为关键功能提供集成工具,例如跨所有组件监视、调试和测试流应用程序。
要了解更多信息,可以参阅Apache Kafka、Apache Flink和Apache Pinot的官方文档和示例。围绕这些项目的社区也有丰富的资源,包括书籍、教程和技术讲座,涵盖了现实世界的用例和最佳实践。
额外的资源:
- Apache Kafka Patterns and Anti-Patterns by Abhishek Gupta, DZone Refcard
- Apache Kafka Essentials by Sudip Sengupta, DZone Refcard
原文:Real-Time Streaming Architectures: A Technical Deep Dive Into Kafka, Flink, and Pinot,作者:Abhishek Gupta