web-dev-qa-db-ja.com

Spring Kafka ProducerはKafka 1.0.0に送信しません(Magic v1はレコードヘッダーをサポートしません))

Kafkaローカルで設定するためにこのdocker-composeセットアップを使用しています: https://github.com/wurstmeister/kafka-docker/

docker-compose upは正常に動作し、シェルを介してトピックを作成すると正常に動作します。

今、私はKafka経由でspring-kafka:2.1.0.RELEASE経由で接続しようとします

Springアプリケーションを起動すると、正しいバージョンのKafkaが出力されます。

o.a.kafka.common.utils.AppInfoParser     : Kafka version : 1.0.0
o.a.kafka.common.utils.AppInfoParser     : Kafka commitId : aaa7af6d4a11b29d

私はこのようなメッセージを送ろうとします

kafkaTemplate.send("test-topic", UUID.randomUUID().toString(), "test");

クライアント側での送信が失敗します

UnknownServerException: The server experienced an unexpected error when processing the request

サーバーコンソールでメッセージを取得しますMagic v1はレコードヘッダーをサポートしていません

Error when handling request {replica_id=-1,max_wait_time=100,min_bytes=1,max_bytes=2147483647,topics=[{topic=test-topic,partitions=[{partition=0,fetch_offset=39,max_bytes=1048576}]}]} (kafka.server.KafkaApis)
Java.lang.IllegalArgumentException: Magic v1 does not support record headers

グーグルはバージョンの競合を示唆していますが、バージョンは適合するようです(org.Apache.kafka:kafka-clients:1.0.0はクラスパスにあります)。

手がかりはありますか?ありがとう!

編集:問題の原因を絞り込みました。プレーンな文字列の送信は機能しますが、JsonSerializerを介してJsonを送信すると、特定の問題が発生します。プロデューサー設定の内容は次のとおりです。

@Value("\${kafka.bootstrap-servers}")
lateinit var bootstrapServers: String

@Bean
fun producerConfigs(): Map<String, Any> =
        HashMap<String, Any>().apply {
            // list of Host:port pairs used for establishing the initial connections to the Kakfa cluster
            put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers)
            put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer::class.Java)
            put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer::class.Java)
        }

@Bean
fun producerFactory(): ProducerFactory<String, MyClass> =
        DefaultKafkaProducerFactory(producerConfigs())

@Bean
fun kafkaTemplate(): KafkaTemplate<String, MyClass> =
        KafkaTemplate(producerFactory())
10
DerM

解決しました。問題は、ブローカーでも、一部のドッカーキャッシュでも、Springアプリでもありません。

問題は、デバッグに並行して使用するコンソールコンシューマーでした。これはkafka-console-consumer.sh --topic=topic --zookeeper=...で始まる「古い」消費者でした

実際に起動すると警告を表示します:Using the ConsoleConsumer with old consumer is deprecated and will be removed in a future major release. Consider using the new consumer by passing [bootstrap-server] instead of [zookeeper].

--bootstrap-serverオプションを指定した「新しい」コンシューマーを使用する必要があります(特にKafka 1.0をJsonSerializerで使用する場合)。注:ここで古いコンシューマーを使用すると、プロデューサーに影響する可能性があります。

3
DerM

同様の問題がありました。 Kafkaは、値にJsonSerializerまたはJsonSerdeを使用する場合、デフォルトでヘッダーを追加します。この問題を防ぐには、情報ヘッダーの追加を無効にする必要があります。

デフォルトのJSONシリアル化で問題ない場合は、次を使用します(ここでのキーポイントはADD_TYPE_INFO_HEADERS):

Map<String, Object> props = new HashMap<>(defaultSettings);
props.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, false);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
ProducerFactory<String, Object> producerFactory = new DefaultKafkaProducerFactory<>(props);

ただし、特定のJsonSerializerを持つカスタムObjectMapperが必要な場合(PropertyNamingStrategy.SNAKE_CASE)、spring kafka=はJsonSerializerのプロパティを無視するので、DefaultKafkaProducerFactoryに明示的に情報ヘッダーを追加することを無効にする必要がありますADD_TYPE_INFO_HEADERS(私にとっては、春カフカの悪いデザインです)

JsonSerializer<Object> valueSerializer = new JsonSerializer<>(customObjectMapper);
valueSerializer.setAddTypeInfo(false);
ProducerFactory<String, Object> producerFactory = new DefaultKafkaProducerFactory<>(props, Serdes.String().serializer(), valueSerializer);

またはJsonSerdeを使用する場合:

Map<String, Object> jsonSerdeProperties = new HashMap<>();
jsonSerdeProperties.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, false);
JsonSerde<T> jsonSerde = new JsonSerde<>(serdeClass);
jsonSerde.configure(jsonSerdeProperties, false);
17

私は問題なくそのdockerイメージに対してテストを実行しました...

$docker ps

CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                                                NAMES
f093b3f2475c        kafkadocker_kafka        "start-kafka.sh"         33 minutes ago      Up 2 minutes        0.0.0.0:32768->9092/tcp                              kafkadocker_kafka_1
319365849e48        wurstmeister/zookeeper   "/bin/sh -c '/usr/sb…"   33 minutes ago      Up 2 minutes        22/tcp, 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp   kafkadocker_zookeeper_1

@SpringBootApplication
public class So47953901Application {

    public static void main(String[] args) {
        SpringApplication.run(So47953901Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(KafkaTemplate<Object, Object> template) {
        return args -> template.send("foo", "bar", "baz");
    }

    @KafkaListener(id = "foo", topics = "foo")
    public void listen(String in) {
        System.out.println(in);
    }

}

spring.kafka.bootstrap-servers=192.168.177.135:32768
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=false

2017-12-23 13:27:27.990  INFO 21305 --- [      foo-0-C-1] o.s.k.l.KafkaMessageListenerContainer    : partitions assigned: [foo-0]
baz

[〜#〜] edit [〜#〜]

それでも私のために働く...

spring.kafka.bootstrap-servers=192.168.177.135:32768
spring.kafka.consumer.auto-offset-reset=earliest
spring.kafka.consumer.enable-auto-commit=false
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer

2017-12-23 15:27:59.997  INFO 44079 --- [           main] o.a.k.clients.producer.ProducerConfig    : ProducerConfig values: 
    acks = 1
    ...
    value.serializer = class org.springframework.kafka.support.serializer.JsonSerializer

...

2017-12-23 15:28:00.071  INFO 44079 --- [      foo-0-C-1] o.s.k.l.KafkaMessageListenerContainer    : partitions assigned: [foo-0]
baz
1
Gary Russell