【发布时间】:2022-04-02 21:23:56
【问题描述】:
版本:
- 弹簧靴:2.4.1
- Kafka 客户端:2.6.0
由于某些系统限制,Kafka Producer 被配置为单独发送每条消息。具体来说,通过设置linger.ms = 0 和max.batch.size = 0 禁用批处理。
因此,从 Kafka 的客户端角度来看,每条消息都是新批次。我想在所有可用分区之间平均分配消息,这就是我配置客户端RoundRobinPartitioner 来实现它的原因。
但是,当一个节点关闭并且我有偶数个分区时对配置进行测试,我发现消息分布在所有可用分区的一半之间。这种行为的原因是在KafkaProducer.doSend(..)'中双重调用partitioner.partition(..)。由于 RoundRobinPartitioner.partition() 在后台递增计数器并返回除以可用分区号的余数,因此在一个记录发布中调用它两次会导致跳过每个第二个分区。
例如,availablePartitions 包含 6 个分区 (1-6)。通过KafkaProducer.doSend(..) 两次调用partition(..) 总是跳过1,3,5 个分区。
private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) {
..
int partition = partition(record, serializedKey, serializedValue, cluster);
..
RecordAccumulator.RecordAppendResult result = accumulator.append(tp, timestamp, serializedKey,
serializedValue, headers, interceptCallback, remainingWaitMs, true, nowMs);
//Since I disabled batches this if is always true
if (result.abortForNewBatch) {
int prevPartition = partition;
partitioner.onNewBatch(record.topic(), cluster, prevPartition);
partition = partition(record, serializedKey, serializedValue, cluster);
tp = new TopicPartition(record.topic(), partition);
if (log.isTraceEnabled()) {
log.trace("Retrying append due to new batch creation for topic {} partition {}. The old partition was {}", record.topic(), partition, prevPartition);
}
// producer callback will make sure to call both 'callback' and interceptor callback
interceptCallback = new InterceptorCallback<>(callback, this.interceptors, tp);
result = accumulator.append(tp, timestamp, serializedKey,
serializedValue, headers, interceptCallback, remainingWaitMs, false, nowMs);
}
- 虽然很容易重新实现,但我想知道这种行为是否 想要?
- 如果当前批次更新分区的原因是什么 关门了吗?
- 我相信我不是第一个,How 社区 克服了这种设计?
【问题讨论】:
标签: spring apache-kafka