使用kafka-avro-console-consumer时遇Error 40101问题求助
我之前碰到过完全一样的问题,结合你的排查信息,咱们来拆解下原因和可行的解决办法:
问题回顾
你的当前环境与遇到的矛盾点:
- 环境:Kafka 3.2(客户端+服务端)搭配Aiven Karapace Schema Registry
- 矛盾:用
curl携带凭证能正常查询Schema Registry,但kafka-avro-console-consumer无论通过URL嵌入凭证还是指定USER_INFO方式,都返回40101 Unauthorized错误;改用kafka-console-consumer.sh能正常连接,但只能看到字节流,无法反序列化Avro消息
错误日志如下:
[2023-01-17T18:00:14.960189+0100] [2023-01-17 18:00:14,957] ERROR Unknown error when running consumer: (kafka.tools.ConsoleConsumer$:105) [2023-01-17T18:00:14.960210+0100] org.apache.kafka.common.errors.SerializationException: Error retrieving Avro schema for id 119 [2023-01-17T18:00:14.960230+0100] Caused by: io.confluent.kafka.schemaregistry.client.rest.exceptions.RestClientException: Unauthorized; error code: 40101 [2023-01-17T18:00:14.960249+0100] at io.confluent.kafka.schemaregistry.client.rest.RestService.sendHttpRequest(RestService.java:170) [2023-01-17T18:00:14.960272+0100] at io.confluent.kafka.schemaregistry.client.rest.RestService.httpRequest(RestService.java:188) [2023-01-17T18:00:14.960293+0100] at io.confluent.kafka.schemaregistry.client.rest.RestService.getId(RestService.java:330) [2023-01-17T18:00:14.960312+0100] at io.confluent.kafka.schemaregistry.client.rest.RestService.getId(RestService.java:323) [2023-01-17T18:00:14.960332+0100] at io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient.getSchemaByIdFromRegistry(CachedSchemaRegistryClient.java:63) [2023-01-17T18:00:14.960353+0100] at io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient.getBySubjectAndID(CachedSchemaRegistryClient.java:118) [2023-01-17T18:00:14.960372+0100] at io.confluent.kafka.serializers.AbstractKafkaAvroDeserializer.deserialize(AbstractKafkaAvroDeserializer.java:121) [2023-01-17T18:00:14.960391+0100] at io.confluent.kafka.serializers.AbstractKafkaAvroDeserializer.deserialize(AbstractKafkaAvroDeserializer.java:92) [2023-01-17T18:00:14.960412+0100] at io.confluent.kafka.formatter.AvroMessageFormatter.writeTo(AvroMessageFormatter.java:120) [2023-01-17T18:00:14.960431+0100] at io.confluent.kafka.formatter.AvroMessageFormatter.writeTo(AvroMessageFormatter.java:112) [2023-01-17T18:00:14.960449+0100] at kafka.tools.ConsoleConsumer$.process(ConsoleConsumer.scala:137) [2023-01-17T18:00:14.960468+0100] at kafka.tools.ConsoleConsumer$.run(ConsoleConsumer.scala:75) [2023-01-17T18:00:14.960487+0100] at kafka.tools.ConsoleConsumer$.main(ConsoleConsumer.scala:50) [2023-01-17T18:00:14.960506+0100] at kafka.tools.ConsoleConsumer.main(ConsoleConsumer.scala)
核心原因
你已经摸到了问题的关键:Java的java.net.HttpURLConnection默认会自动剥离URL中的用户名和密码凭证,而Kafka 3.2对应的Confluent Schema Registry客户端版本,还不支持通过独立配置项传递基础认证信息,导致consumer请求Schema Registry时根本没携带有效授权信息,直接触发401错误。你的测试代码也验证了这一点——用含凭证的URL创建HttpURLConnection时,请求会因缺少认证失败。
解决方案
方案1:使用独立认证配置项(推荐)
如果你的Schema Registry客户端版本支持(Confluent 6.2+部分版本开始支持,7.0+完全支持),可以改用独立的认证配置,绕过URL凭证被剥离的问题:
kafka-avro-console-consumer \ --bootstrap-server $KAFKA_HOST:$KAFKA_PORT \ --consumer.config /home/guido/.tls/kafka/client-tls.properties \ --property schema.registry.url=https://$SCHEMA_REGISTRY_HOST:$SCHEMA_REGISTRY_PORT \ --property basic.auth.credentials.source=USER_INFO \ --property schema.registry.basic.auth.user.info=$SCHEMA_REGISTRY_USER:$SCHEMA_REGISTRY_PASSWORD \ --topic my-topic
这个方案通过basic.auth.credentials.source=USER_INFO指定从schema.registry.basic.auth.user.info读取凭证,完全不依赖URL传递,避开了HttpURLConnection的限制。
方案2:修改JVM参数强制保留URL凭证(临时 workaround)
如果方案1不生效(比如客户端版本太旧),可以通过设置JVM系统属性,让HttpURLConnection保留URL中的认证信息:
java -Djdk.http.auth.tunneling.disabledSchemes="" \ -cp $(find /path/to/confluent/lib -name '*.jar' | tr '\n' ':') \ kafka.tools.ConsoleConsumer \ --bootstrap-server $KAFKA_HOST:$KAFKA_PORT \ --consumer.config /home/guido/.tls/kafka/client-tls.properties \ --formatter io.confluent.kafka.formatter.AvroMessageFormatter \ --property schema.registry.url=https://$SCHEMA_REGISTRY_USER:$SCHEMA_REGISTRY_PASSWORD@$SCHEMA_REGISTRY_HOST:$SCHEMA_REGISTRY_PORT \ --property basic.auth.credentials.source=URL \ --topic my-topic
注意替换/path/to/confluent/lib为你实际的Confluent库路径,这个方法直接调用Java类并设置JVM参数,绕过脚本的限制。
方案3:升级Schema Registry客户端版本
Confluent后续版本已经修复了这个问题,全面支持schema.registry.basic.auth.user.info配置。如果可以的话,升级到Confluent Platform 7.0+(与Kafka 3.2兼容),然后使用方案1的配置即可正常工作。
内容的提问来源于stack exchange,提问作者Jodiug

