Flink 1.11.1 FlinkKafkaProducer写入topic0分区问题记录
问题记录:
flink版本:1.11.1
使用FlinkKafkaProducer往下游发送数据,代码如下:
Properties props = new Properties();
props.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"kafkatest:9092");
FlinkKafkaProducer<String> producer = new FlinkKafkaProducer<>("partition_test_3",new SimpleStringSchema(),props);
dataStream.flatMap(new RichFlatMapFunction<String, String>() {
@Override
public void flatMap(String s, Collector<String> collector) throws Exception {
int thisSubtask = getRuntimeContext().getIndexOfThisSubtask();
int parallelSubtasks = getRuntimeContext().getNumberOfParallelSubtasks();
System.out.println("thisSubtask:"+thisSubtask+", parallelSubtasks:"+parallelSubtasks+" value:"+s);
collector.collect(s);
}
}).addSink(producer);
上游kafkatopic有10个分区,flink开启10并行度消费topic,发现下游topic 三个partition,只有一个partition_0有数据。
查看flink 1.11.1 FlinkKafkaProducer源码发现,最终创建FlinkKafkaProducer调用下图红框部分
其中:KafkaSerializationSchema 参数传递的是KafkaSerializationSchemaWrapper。而FlinkKakfaProducer在没有指定分区器的情况下默认使用的是
FlinkFixedPartitioner,源码如下:
public class FlinkFixedPartitioner<T> extends FlinkKafkaPartitioner<T> {
private static final long serialVersionUID = -3785320239953858777L;
private int parallelInstanceId;
@Override
public void open(int parallelInstanceId, int parallelInstances) {
Preconditions.checkArgument(parallelInstanceId >= 0, "Id of this subtask cannot be negative.");
Preconditions.checkArgument(parallelInstances > 0, "Number of subtasks must be larger than 0.");
this.parallelInstanceId = parallelInstanceId;
}
@Override
public int partition(T record, byte[] key, byte[] value, String targetTopic, int[] partitions) {
Preconditions.checkArgument(
partitions != null && partitions.length > 0,
"Partitions of the target topic is empty.");
return partitions[parallelInstanceId % partitions.length];
}
@Override
public boolean equals(Object o) {
return this == o || o instanceof FlinkFixedPartitioner;
}
@Override
public int hashCode() {
return FlinkFixedPartitioner.class.hashCode();
}
}
可以看到
FlinkFixedPartitioner继承自FlinkKafkaPartitioner,并重写了open方法,其获取分区的逻辑是Flink当前的 子任务号对topic的partition数量取模(partitions[parallelInstanceId % partitions.length])
但是实际上1.11.1为什么只写到一个分区了呢?
看到FlinkKafkaPartitioner源码:
使用之前如果没有进行重写open方法,那么子任务号,默认就是0。
这时候返回去看 KafkaSerializationSchemaWrapper。
发现其并没有对partitioner进行open重写。
Flink Issues:
https://issues.apache.org/jira/browse/FLINK-19285?jql=project%20%3D%20FLINK%20AND%20text%20~%20%22kafka%20partitioner%22
官方在Flink1.11.2中已修复,那来看一下1.11.2版本中的KafkaSerializationSchemaWrapper:
果然进行了FlinkFixedPartitioner的初始化。
1.11.2 代码测试:
上游10个分区,flink并行度10,下游topic三个分区,更换
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka_2.11</artifactId>
<version>1.11.2</version>
</dependency>
任务执行后下游三个分区均有数据写入!