【问题标题】:Producer cant distrubute messages to multiple consumers?生产者不能将消息分发给多个消费者?
【发布时间】:2020-10-31 10:43:38
【问题描述】:

我正在尝试使用带有--scale 标志的 docker-compose 和 docker-compose.yaml 中的转发端口(如“8070-8072:8070”)自动扩展 java spring 框架 kafka 消费者。所以当我触发发布消息的端点时,它做得很好。但在消费者方面,只有 1 个消费者消费所有消息。我有 3 个具有相同组 ID 和不同客户端 ID 的消费者。我想要的是分布式消息传递。我阅读了一些关于分区的论文,并查看了我的日志。似乎只有1个分区。是这个原因吗?我怎样才能做到这一点?我将添加日志、消费者配置、发布者配置和 docker-compose 文件。首先是log。似乎只有 1 个中有 3 个有分区。

命令:

docker-compose up --build --scale nonwebapp=3 --scale webapp=3

docker-compose.yaml

kafka:
        image: confluentinc/cp-kafka:latest
        depends_on:
            - zookeeper
        ports:
            - 9092:9092
        environment:
            KAFKA_LOG_DIRS: "/kafka/kafka-logs"
            KAFKA_BROKER_ID: 1
            KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
            KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
            KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
            KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
            KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
            KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        restart: always
            
    webapp:
        build: benchmark.web
        command: bash -c "while !</dev/tcp/kafka/29092; do >&2 echo 'Waiting for kafka to up...' sleep 1; done;"
        ports: 
            - "8070-8072:8070"
        volumes:
            - ./logs:/logs
            - ${GCP_KEY_PATH}:/root/keys/keyfile.json:ro
        depends_on:
          - kafka
        environment:
          SPRING_KAFKA_BOOTSTRAPSERVERS: kafka:29092
          TZ: "Asia/Istanbul"
          GOOGLE_APPLICATION_PROJECT_ID: apt-cubist-282712
          GOOGLE_APPLICATION_CREDENTIALS: /root/keys/keyfile.json
        restart: always
            
            
    nonwebapp:
        build: benchmark.nonweb
        command: bash -c "while !</dev/tcp/kafka/29092; do >&2 echo 'Waiting for kafka to up...' sleep 1; done;"
        depends_on:
          - kafka
        volumes:
          - ${GCP_KEY_PATH}:/root/keys/keyfile.json:ro
        ports:
          - "8060-8062:8060"
        environment:
          SPRING_KAFKA_BOOTSTRAPSERVERS: kafka:29092
          GOOGLE_APPLICATION_PROJECT_ID: apt-cubist-282712
          GOOGLE_APPLICATION_CREDENTIALS: /root/keys/keyfile.json
          TZ: "Asia/Istanbul"
        restart: always

生产者配置

@Bean
    ProducerFactory<String, byte[]> producerFactory(){
        Map<String, Object> configProps = new HashMap<>();
        configProps.put(
                ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
                kafkaInContainerAdress);

    /*
        configProps.put(
                ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
                kafkaInLocal);
*/
        configProps.put(
                ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
                StringSerializer.class
        );
        configProps.put(
                ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
                ByteArraySerializer.class
        );
        return new DefaultKafkaProducerFactory<>(configProps);
    }

    @Bean
    public KafkaTemplate<String,byte[]> kafkaTemplate(){

        return new KafkaTemplate<>(producerFactory());
    }

消费者配置

 @Bean
    public ConsumerFactory<String, byte[]> consumerFactory() {
        Map<String, Object> props = new HashMap<>();
       props.put(
                ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
                kafkaInContainerAdress);
       /*
        props.put(
                ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
                kafkaInLocal);
*/
        props.put(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
                "org.apache.kafka.clients.consumer.RoundRobinAssignor");
        props.put(ConsumerConfig.CLIENT_ID_CONFIG, r.nextInt());
        props.put(
                ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class);
        props.put(
                ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                ByteArrayDeserializer.class);
        props.put("group.id","topic_trial_consumers");
        return new DefaultKafkaConsumerFactory<>(props);
    }

    @Bean
    public ConcurrentKafkaListenerContainerFactory<String, byte[]>
    kafkaListenerContainerFactory() {

        ConcurrentKafkaListenerContainerFactory<String, byte[]> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        return factory;
    }

【问题讨论】:

    标签: java spring-boot docker apache-kafka messaging


    【解决方案1】:

    似乎只有 1 个分区。是这个原因吗?

    是的,如果只有一个分区,则只有一个消费者(来自消费者组)可以消费它,其他消费者(来自同一组)即使启动也会处于空闲状态。

    似乎只有 1 个中有 3 个有分区

    从您的图像中,我可以看到topic_trial-0。所以它是topic_trial 的第一个分区。

    增加编号。分区数,例如 3 个,并使用相同的 group.id 启动三个消费者,负载应该被分配(每个分区一个)。

    【讨论】:

    • 是的,你是对的,但我不知道如何增加主题的分区。有没有办法配置这个表单 ProducerConfig 或知道我该怎么做?
    • @KadirAkin 它不是生产者配置或消费者配置。这是一个主题配置。您可以通过 Kafka 自带的kafka-topics 工具来增加它
    • @KadirAkin 例如,./kafka-topics.sh --alter --topic topic_trial --bootstrap-server localhost:9092 --partitions 3(此 .sh 文件通常会出现在您的 Kafka 安装目录中)
    • 我明白了,在我的情况下,我使用 docker,并且我有一个像 KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" 这样的环境变量。我首先进行了研究,因为我不想让你有很多问题:D 但我找不到。我将如何为自动创建的主题增加分区?感谢您的帮助。我尝试添加为command: "bash -c ' kafka-topics --create --if-not-exists --zookeeper zookeeper:2181 --partitions 3 --replication-factor 1 --topic orders '" 之类的命令,但在构建Replication factor: 1 larger than available brokers: 0. 时会出错
    • 我解决了切换 wurstmeister 图像的问题。它支持从 docker-compose 创建带有分区和复制编号的主题。顺便说一句,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    相关资源
    最近更新 更多