Kafka DataStream连接器支持通过DataStream API读取和写入Kafka数据。本文介绍连接器的使用方法和参数配置。
Kafka Source
通过DataStream的方式读写数据时,则需要使用对应的DataStream连接器连接实时计算Flink版,DataStream连接器设置方法请参见DataStream连接器使用方法。
Kafka Source提供了构建类来创建Kafka Source的实例。我们将通过以下示例代码介绍如何构建Kafka Source来消费input-topic最早位点的数据,消费组名称为my-group,并将Kafka消息体反序列化为字符串。
Java
KafkaSource<String> source = KafkaSource.<String>builder()
.setBootstrapServers(brokers)
.setTopics("input-topic")
.setGroupId("my-group")
.setStartingOffsets(OffsetsInitializer.earliest())
.setValueOnlyDeserializer(new SimpleStringSchema())
.build();
env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Source");在构建KafkaSource时,必须指定以下参数。
参数 | 说明 |
BootstrapServers | Kafka Broker地址,通过setBootstrapServers(String)方法配置。 |
GroupId | 消费者组ID,通过setGroupId(String)方法配置。 |
Topics或Partition | 订阅的Topic或Partition名称。Kafka Source提供了以下三种Topic或Partition的订阅方式:
|
Deserializer | 解析Kafka消息的反序列化器。 反序列化器通过setDeserializer(KafkaRecordDeserializationSchema)来指定,其中KafkaRecordDeserializationSchema定义了如何解析Kafka的ConsumerRecord。如果只解析Kafka消息中的消息体(Value)的数据,可以通过以下任何一种方式实现:
说明 如果需要完整地解析ConsumerRecord,则需要自行实现KafkaRecordDeserializationSchema接口。 |
XML
Maven中央库中已经放置了Kafka DataStream连接器。
<dependency>
<groupId>com.alibaba.ververica</groupId>
<artifactId>ververica-connector-kafka</artifactId>
<version>${vvr-version}</version>
</dependency>在使用Kafka DataStream连接器时,需要了解以下Kafka属性:
起始消费位点
Kafka Source能够通过位点初始化器(OffsetsInitializer)来指定从不同的偏移量开始消费。内置的位点初始化器包括以下内容。
位点初始化器
代码设置
从最早位点开始消费。
KafkaSource.builder().setStartingOffsets(OffsetsInitializer.earliest())从最末尾位点开始消费。
KafkaSource.builder().setStartingOffsets(OffsetsInitializer.latest())从时间戳大于等于指定时间的数据开始消费,单位为毫秒。
KafkaSource.builder().setStartingOffsets(OffsetsInitializer.timestamp(1592323200000L))从消费组提交的位点开始消费,如果提交位点不存在,使用最早位点。
KafkaSource.builder().setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.EARLIEST))从消费组提交的位点开始消费,不指定位点重置策略。
KafkaSource.builder().setStartingOffsets(OffsetsInitializer.committedOffsets())说明如果以上内置的初始化器不能满足需求,也可以自己实现自定义的位点初始化器。
如果未指定位点初始化器,则默认使用OffsetsInitializer.earliest(),即最早位点。
流模式和批模式
Kafka Source支持流式和批式两种运行模式。默认情况下,Kafka Source设置为以流模式运行,因此作业永远不会停止,直到Flink作业失败或被取消。如果要配置Kafka Source在批模式下运行,可以使用setBounded(OffsetsInitializer)指定停止偏移量,当所有分区都达到其停止偏移量时,Kafka Source会退出运行。
说明通常,流模式下Kafka Source没有停止偏移量。为了方便对代码进行调试,流模式下可以使用 setUnbounded(OffsetsInitializer) 指定停止偏移量。请留意指定流模式和批模式停止偏移量的方法名(setUnbounded 和 setBounded)是不同的。
动态分区检查
为了在不重启Flink作业的情况下,处理Topic扩容或新建Topic等场景,可以在提供的Topic或Partition订阅模式下,启用动态分区检查功能。DataStream连接器中,该功能默认关闭,需要手动显式配置开启:
KafkaSource.builder() .setProperty("partition.discovery.interval.ms", "10000") // 每10秒检查一次新分区。重要动态分区检查功能依赖于Kafka集群的元信息更新机制。如果Kafka集群未及时更新分区信息,可能导致新分区无法被发现。请确保Kafka集群的partition.discovery.interval.ms配置与实际情况匹配。
事件时间和水印
Kafka Source默认使用Kafka消息中的时间戳作为事件时间。可以自定义水印策略(Watermark Strategy)以从消息中提取事件时间,并向下游发送水印。
env.fromSource(kafkaSource, new CustomWatermarkStrategy(), "Kafka Source With Custom Watermark Strategy")如果需要了解自定义水印策略(Watermark Strategy),请参见Generating Watermarks。
说明若并行Source的部分任务长期处于空闲状态(如某个Kafka分区长时间无数据输入,或Source并发数超过Kafka分区数量),可能导致Watermark生成机制失效。此时系统将无法正常触发窗口计算,造成数据处理流程停滞。
为解决此类问题,可通过以下方式调整:
配置Watermark超时机制:启用table.exec.source.idle-timeout参数,强制系统在指定超时时间后生成Watermark,确保窗口计算周期的推进。
数据源优化:建议保持Kafka分区数与Source并发度的合理比例(推荐分区数≥Source并行度)。
消费位点提交
Kafka Source在Checkpoint完成时,提交当前的消费位点,以保证Flink的Checkpoint状态和Kafka Broker上的提交位点一致。如果未开启Checkpoint,Kafka Source依赖于Kafka Consumer内部的位点定时自动提交逻辑,自动提交功能由enable.auto.commit和 auto.commit.interval.ms两个Kafka Consumer配置项进行配置。
说明Kafka Source不依赖于Broker上提交的位点来恢复失败的作业。提交位点只是为了上报Kafka Consumer和消费组的消费进度,以在Broker端进行监控。
其他属性
除了上述属性之外,还可以使用setProperties(Properties) 和setProperty(String, String) 为Kafka Source和Kafka Consumer设置任意属性。KafkaSource通常有以下配置项。
配置项
说明
client.id.prefix
指定用于Kafka Consumer的客户端ID前缀。
partition.discovery.interval.ms
定义Kafka Source检查新分区的时间间隔。
说明partition.discovery.interval.ms会在批模式下被覆盖为-1。
register.consumer.metrics
指定是否在Flink中注册Kafka Consumer的指标。
其他Kafka Consumer配置
Kafka Consumer的配置详情,请参见Apache Kafka。
重要Kafka Connector会强制覆盖部分手动配置的参数项,覆盖详情如下:
key.deserializer始终被覆盖为ByteArrayDeserializer。
value.deserializer始终被覆盖为ByteArrayDeserializer。
auto.offset.reset.strategy被覆盖为OffsetsInitializer#getAutoOffsetResetStrategy()。
以下示例展示如何配置Kafka Consumer,以使用PLAIN作为SASL机制并提供JAAS配置。
KafkaSource.builder() .setProperty("sasl.mechanism", "PLAIN") .setProperty("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"username\" password=\"password\";")监控
Kafka Source在Flink中注册指标,用于监控和诊断。
指标范围
Kafka source reader的所有指标都注册在KafkaSourceReader指标组下,KafkaSourceReader是operator指标组的子组。与特定主题分区相关的指标注册在KafkaSourceReader.topic.<topic_name>.partition.<partition_id>指标组中。
例如Topic "my-topic"、分区1的当前消费位点(currentOffset)注册在<some_parent_groups>.operator.KafkaSourceReader.topic.my-topic.partition.1.currentOffset。成功提交位点的次数(commitsSucceeded)注册在<some_parent_groups>.operator.KafkaSourceReader.commitsSucceeded。
指标列表
指标名称
描述
范围
currentOffset
当前消费位点
TopicPartition
committedOffset
当前提交位点
TopicPartition
commitsSucceeded
成功提交的次数
KafkaSourceReader
commitsFailed
失败的提交次数
KafkaSourceReader
Kafka Consumer指标
Kafka Consumer的指标注册在指标组KafkaSourceReader.KafkaConsumer。例如Kafka Consumer指标records-consumed-total注册在<some_parent_groups>.operator.KafkaSourceReader.KafkaConsumer.records-consumed-total。
可以使用配置项register.consumer.metrics配置是否注册Kafka消费者的指标。默认此选项设置为true。对于Kafka Consumer的指标,可参见Apache Kafka。
Kafka Sink
Flink Kafka Sink可以实现将流数据写入一个或多个Kafka Topic。
DataStream<String> stream = ...
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", );
KafkaSink<String> kafkaSink =
KafkaSink.<String>builder()
.setKafkaProducerConfig(kafkaProperties) // // producer config
.setRecordSerializer(
KafkaRecordSerializationSchema.builder()
.setTopic("my-topic") // target topic
.setKafkaValueSerializer(StringSerializer.class) // serialization schema
.build())
.setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE) // fault-tolerance
.build();
stream.sinkTo(kafkaSink);需要配置以下参数。
参数 | 说明 |
Topic | 数据写入的默认Topic名称。 |
数据序列化 | 构建时需要提供 用户可以对每条数据如何写入Kafka进行细粒度地控制。通过ProducerRecord可以进行以下操作:
|
Kafka客户端属性 | bootstrap.servers必填,以逗号分隔的Kafka Broker列表。 |
容错语义 | 启用Flink的Checkpoint后,Flink Kafka Sink可以保证精确一次的语义。除了启用Flink的Checkpoint外,还可以通过DeliveryGuarantee参数来指定不同的容错语义,DeliveryGuarantee参数详情如下:
|
EXACTLY_ONCE语义注意事项
配置消费者隔离级别
所有消费 Kafka 数据的应用必须设置 isolation.level:
read_committed:只读取已提交的数据。read_uncommitted(默认):可读取未提交的数据。
EXACTLY_ONCE 依赖
read_committed。否则消费者可能看到未提交数据,破坏一致性。事务超时与数据丢失
Flink 从 Checkpoint 恢复时,仅依赖该 Checkpoint 开始前已提交的事务。如果作业崩溃到重启的时间超过 Kafka 事务超时,Kafka 会自动中止事务,导致数据丢失。
Kafka Broker 默认
transaction.max.timeout.ms= 15 分钟。Flink Kafka Sink 默认设置
transaction.timeout.ms= 1 小时。你必须在 Broker 端提高
transaction.max.timeout.ms,使其不小于 Flink 的设置。
Producer 池与 Checkpoint 并发
EXACTLY_ONCE 模式使用固定大小的 Kafka Producer 池。每个 Checkpoint 占用池中的一个 Producer。如果并发 Checkpoint 数超过池大小,作业会失败。
请根据最大并发 Checkpoint 数调整 Producer 池大小。
并行度缩容限制
如果作业在第一个 Checkpoint 前失败,重启后不会保留原有 Producer 池信息。因此,在第一个 Checkpoint 完成前,不要缩减作业并行度。如必须缩容,并行度不得低于
FlinkKafkaProducer.SAFE_SCALE_DOWN_FACTOR。事务阻塞读取
在
read_committed模式下,任何未结束(未提交也未中止)的事务会阻塞整个 Topic 的读取。例如:
事务 1 写入数据。
事务 2 写入并提交数据。
只要事务 1 未结束,事务 2 的数据对消费者不可见。
因此:
正常运行时,数据可见延迟约等于 Checkpoint 间隔。
作业失败时,正在写入的 Topic 会阻塞消费者,直到作业重启或事务超时,极端情况下,事务超时甚至会影响读取。