Apache kafka 使用Kafka Connect读取AVRO编码的消息(由KSQL流创建)时出现问题

Apache kafka 使用Kafka Connect读取AVRO编码的消息(由KSQL流创建)时出现问题,apache-kafka,apache-kafka-connect,confluent-schema-registry,ksqldb,Apache Kafka,Apache Kafka Connect,Confluent Schema Registry,Ksqldb,当我们通过KSQL创建AVRO消息并尝试使用Kafka-Connect使用它们时,会发生一些奇怪的事情。一点背景: 源数据 一个第三方提供商正在以JSON的形式在我们的Kafka集群上生成数据(到目前为止还不错)。我们实际上看到了数据 数据转换 由于我们的内部系统要求数据在AVRO中编码,我们创建了一个KSQL集群,通过在KSQL中创建以下流将传入数据转换为AVRO: { "ksql": " CREATE STREAM src_stream (browser_name V

当我们通过KSQL创建AVRO消息并尝试使用Kafka-Connect使用它们时,会发生一些奇怪的事情。一点背景:

源数据 一个第三方提供商正在以JSON的形式在我们的Kafka集群上生成数据(到目前为止还不错)。我们实际上看到了数据

数据转换 由于我们的内部系统要求数据在AVRO中编码,我们创建了一个KSQL集群,通过在KSQL中创建以下流将传入数据转换为AVRO:

{
    "ksql": "
        CREATE STREAM src_stream (browser_name VARCHAR)
        WITH (KAFKA_TOPIC='json_topic', VALUE_FORMAT='JSON');

        CREATE STREAM sink_stream WITH (KAFKA_TOPIC='avro_topic',VALUE_FORMAT='AVRO',  PARTITIONS=1, REPLICAS=3) AS
        SELECT * FROM src_stream;
    ",
    "streamsProperties": {
        "ksql.streams.auto.offset.reset": "earliest"
    }
}
(到目前为止,一切顺利)

随着偏移量的增加,我们看到从JSON主题到AVRO主题生成的数据

然后,我们在(新的)Kafka Connect集群中创建一个Kafka连接器。在某些情况下,我们使用多个Kafka Connect群集(这些群集具有相同的属性),因此,我们有一个Kafka Connect群集运行此数据,但有一个群集的精确副本用于其他AVRO数据(1个用于分析,1个用于我们的业务数据)

此连接器的接收器是BigQuery,我们使用的是Wepay BigQuery接收器连接器1.2.0。同样,到目前为止,一切都很好。我们的业务集群使用此连接器运行良好,业务集群上的AVRO主题正在流入BigQuery

然而,当我们尝试使用前面的KSQL语句创建的AVRO主题时,我们看到抛出了一个异常:/

例外情况如下:

org.apache.kafka.connect.errors.ConnectException: Tolerance exceeded in error handler
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndHandleError(RetryWithToleranceOperator.java:178)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execute(RetryWithToleranceOperator.java:104)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.convertAndTransformRecord(WorkerSinkTask.java:510)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.convertMessages(WorkerSinkTask.java:490)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.poll(WorkerSinkTask.java:321)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.iteration(WorkerSinkTask.java:225)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.execute(WorkerSinkTask.java:193)
 at org.apache.kafka.connect.runtime.WorkerTask.doRun(WorkerTask.java:175)
 at org.apache.kafka.connect.runtime.WorkerTask.run(WorkerTask.java:219)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)
Caused by: org.apache.kafka.connect.errors.DataException: dpt_video_event-created_v2
 at io.confluent.connect.avro.AvroConverter.toConnectData(AvroConverter.java:98)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.lambda$convertAndTransformRecord$0(WorkerSinkTask.java:510)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndRetry(RetryWithToleranceOperator.java:128)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndHandleError(RetryWithToleranceOperator.java:162)
 ... 13 more
Caused by: org.apache.kafka.common.errors.SerializationException: Error retrieving Avro schema for id 0
Caused by: io.confluent.kafka.schemaregistry.client.rest.exceptions.RestClientException: Schema not found; error code: 40403
 at io.confluent.kafka.schemaregistry.client.rest.RestService.sendHttpRequest(RestService.java:209)
 at io.confluent.kafka.schemaregistry.client.rest.RestService.httpRequest(RestService.java:235)
 at io.confluent.kafka.schemaregistry.client.rest.RestService.getId(RestService.java:415)
 at io.confluent.kafka.schemaregistry.client.rest.RestService.getId(RestService.java:408)
 at io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient.getSchemaByIdFromRegistry(CachedSchemaRegistryClient.java:123)
 at io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient.getBySubjectAndId(CachedSchemaRegistryClient.java:190)
 at io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient.getById(CachedSchemaRegistryClient.java:169)
 at io.confluent.kafka.serializers.AbstractKafkaAvroDeserializer.deserialize(AbstractKafkaAvroDeserializer.java:121)
 at io.confluent.kafka.serializers.AbstractKafkaAvroDeserializer.deserializeWithSchemaAndVersion(AbstractKafkaAvroDeserializer.java:243)
 at io.confluent.connect.avro.AvroConverter$Deserializer.deserialize(AvroConverter.java:134)
 at io.confluent.connect.avro.AvroConverter.toConnectData(AvroConverter.java:85)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.lambda$convertAndTransformRecord$0(WorkerSinkTask.java:510)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndRetry(RetryWithToleranceOperator.java:128)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndHandleError(RetryWithToleranceOperator.java:162)
 at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execute(RetryWithToleranceOperator.java:104)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.convertAndTransformRecord(WorkerSinkTask.java:510)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.convertMessages(WorkerSinkTask.java:490)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.poll(WorkerSinkTask.java:321)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.iteration(WorkerSinkTask.java:225)
 at org.apache.kafka.connect.runtime.WorkerSinkTask.execute(WorkerSinkTask.java:193)
 at org.apache.kafka.connect.runtime.WorkerTask.doRun(WorkerTask.java:175)
 at org.apache.kafka.connect.runtime.WorkerTask.run(WorkerTask.java:219)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)
对我们来说,这表明Kafka Connect正在读取消息,解码AVRO并尝试从模式注册表中获取ID为0的模式。显然,架构注册表中的架构ID始终大于0

我们目前正努力找出问题所在。KSQL似乎正在对架构ID为0的消息进行编码,但我们无法找到原因:/

感谢您的帮助

比尔, 帕特里克

更新: 我们已经为AVRO消息实现了一个基本消费者,该消费者正确地识别了AVRO消息(ID:3)中的模式,因此它似乎被重新命名为Kafka Connect,而不是实际的KSQL/AVRO消息

显然,架构注册表中的架构ID总是>0。。。KSQL似乎正在使用架构ID 0对消息进行编码,但我们无法找到原因

AvroConverter执行“哑检查”,仅查看消耗的字节以
0x0
的魔法字节开始。接下来的4个字节是ID

如果您使用的是
key.converter=AvroConverter
,并且您的密钥以十六进制开头,则ID将在日志中显示为0,并且查找将失败


上次我检查时,KSQL没有以Avro格式输出键,因此您需要检查连接器的属性

是否碰巧将
key.converter
设置为AvroConverter?是的:(这就解决了问题!对于我们的其他集群,我们也使用AVRO作为键,但是当KSQL将它们输出为字符串时,它试图解码键并获取ID为0的模式。我们实际上没有在KSQL中使用键,查询非常简单(如上所示),值是否也一样。converter=AvroConverter?我认为KSQL将自动生成一个ROWKEY?同样的逻辑也适用于值…您也可以使用
kafka avro控制台消费者
查看是否出现相同的错误。添加
--property print.key=true
如果密钥转换器在connect中设置为avro,但一般来说e如果数据确实序列化为Avro,但ID生成为0,则注册表可能存在错误。(您可以查看
/subjects/Avro\u topic-value/versions/latest
)更新上述内容^^^@Patrick您是否尝试过使用我提到的
kafka avro console consumer
?您的示例消费者是否从主题开始就阅读了?