卡夫卡流无法解码StreamTask中的时间戳元数据

时间:2020-04-01 14:01:48

标签: apache-kafka apache-kafka-streams

在启动应用程序期间,我们在Kafka Streams上遇到了奇怪的错误

java.lang.IllegalArgumentException: Illegal base64 character 7b
    at java.base/java.util.Base64$Decoder.decode0(Base64.java:743)
    at java.base/java.util.Base64$Decoder.decode(Base64.java:535)
    at java.base/java.util.Base64$Decoder.decode(Base64.java:558)
    at org.apache.kafka.streams.processor.internals.StreamTask.decodeTimestamp(StreamTask.java:985)
    at org.apache.kafka.streams.processor.internals.StreamTask.initializeTaskTime(StreamTask.java:303)
    at org.apache.kafka.streams.processor.internals.StreamTask.initializeMetadata(StreamTask.java:265)
    at org.apache.kafka.streams.processor.internals.AssignedTasks.initializeNewTasks(AssignedTasks.java:71)
    at org.apache.kafka.streams.processor.internals.TaskManager.updateNewAndRestoringTasks(TaskManager.java:385)
    at org.apache.kafka.streams.processor.internals.StreamThread.runOnce(StreamThread.java:769)
    at org.apache.kafka.streams.processor.internals.StreamThread.runLoop(StreamThread.java:698)
    at org.apache.kafka.streams.processor.internals.StreamThread.run(StreamThread.java:671)

,因此,有关失败的流的错误:ERROR KafkaStreams - stream-client [xxx] All stream threads have died. The instance will be in error state and should be closed.

根据org.apache.kafka.streams.processor.internals.StreamTask中的代码,由于解码时间戳记元数据(StreamTask.decodeTimestamp())中的错误而导致失败。它发生在产品上,无法在舞台上复制。 此类错误的根本原因是什么?

其他信息:我们的应用使用Kafka-Streams,并使用相同的application.idstate.dir使用来自多个kafka经纪人的消息(实际上,我们从一个经纪人切换到另一个经纪人,但是在一段时间内我们连接到两个经纪人,因此我们有两个kafka流,每个经纪人一个。据我了解,消费者组生活在经纪人一方(所以应该不成问题),但是状态目录在客户方。可能是由于对两个kafka流使用相同的state.dir导致了某些竞争状况?可能是根本原因吗?

我们使用具有以下配置的kafka-streams v。2.4.0kafka-clients v。2.4.0,Kafka Broker v。1.1.1

default.key.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
default.value.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
default.timestamp.extractor: org.apache.kafka.streams.processor.WallclockTimestampExtractor
default.deserialization.exception.handler: org.apache.kafka.streams.errors.LogAndContinueExceptionHandler
commit.interval.ms: 5000
num.stream.threads: 1
auto.offset.reset: latest

1 个答案:

答案 0 :(得分:0)

最后,我们找出了某些消费者群体损坏元数据的根本原因。 它是我们的内部监视工具(用pykafka编写)之一,它使暂时不活动的使用者组破坏了元数据。 元数据未加密,并且包含无效数据,如下所示:{"consumer_id": "", "hostname": "monitoring-xxx"}。 为了了解消费者元数据中到底有什么,我们可以使用以下代码:

Map<String, Object> config = Map.of( "group.id", "...", "bootstrap.servers", "...");
String topicName = "...";
Consumer<byte[], byte[]> kafkaConsumer = new KafkaConsumer<byte[], byte[]>(config, new ByteArrayDeserializer(), new ByteArrayDeserializer());
Set<TopicPartition> topicPartitions = kafkaConsumer.partitionsFor(topicName).stream()
        .map(partitionInfo -> new TopicPartition(topicName, partitionInfo.partition()))
        .collect(Collectors.toSet());
kafkaConsumer.committed(topicPartitions).forEach((key, value) ->
    System.out.println("Partition: " + key + " metadata: " + (value != null ? value.metadata() : null)));

用于修复已损坏的元数据的几个选项:

  • 将消费者组更改为一个新的组。请注意,根据latestearliest偏移量重置策略,您可能会丢失或复制消息。因此在某些情况下,此选项可能不可接受
  • 手动覆盖元数据(时间戳根据StreamTask.decodeTimestamp()内部的逻辑进行编码):

    Map<TopicPartition, OffsetAndMetadata> updatedTopicPartitionToOffsetMetadataMap = kafkaConsumer.committed(topicPartitions).entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, (entry) -> new OffsetAndMetadata((entry.getValue()).offset(), "AQAAAXGhcf01"))); kafkaConsumer.commitSync(updatedTopicPartitionToOffsetMetadataMap); 或将元数据指定为Af//////////,在Kafka Streams中表示NO_TIMESTAMP