Kafka4.1.0 队列模式尝鲜

背景

kafka一直以来的消费模型是一个topic下多个partition,每个partition有一个消费者。其中partition的数量决定了消费者的并发度。在KIP-932 的提案中提出了队列模型,在4.0.0版本引入在4.1.0版本为预览版。

使用docker启动

我们使用docker启动一个开启了预览版本的broker。本文使用的native-image

ini 复制代码
docker run -d  \
  -p 9092:9092 \
  --name kafka410 \
  -e KAFKA_NODE_ID=1 \
  -e KAFKA_PROCESS_ROLES=broker,controller \
  -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
  -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \
  -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
  -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \
  -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \
  -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \
  -e KAFKA_NUM_PARTITIONS=3 \
  -e KAFKA_GROUP_COORDINATOR_REBALANCE_PROTOCOLS=classic,consumer,share \
  -e KAFKA_UNSTABLE_API_VERSIONS_ENABLE=true \
  -e KAFKA_GROUP_SHARE_ENABLE=true \
  -e KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR=1 \
  apache/kafka-native:4.1.1-rc1
  • KAFKA_GROUP_COORDINATOR_REBALANCE_PROTOCOLS=classic,consumer,share 在rebalance协议中支持share协议
  • KAFKA_UNSTABLE_API_VERSIONS_ENABLE 解锁未stable的版本限制
  • KAFKA_GROUP_SHARE_ENABLE 开启共享组消费者模式
  • KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR 共享组(队列)模式使用一个topic来保存消费进度,这个是此topic的副本因子

使用spring-kafka消费

  • spring boot 使用的4.0.0-rc2
  • 并添加spring-kafka
    • implementation 'org.springframework.boot:spring-boot-starter-kafka'
java 复制代码
package cc.sofast.practice.kafkagroupconsumer;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ShareKafkaListenerContainerFactory;
import org.springframework.kafka.core.DefaultShareConsumerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ShareConsumerFactory;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.MessageListener;
import org.springframework.kafka.listener.ShareKafkaMessageListenerContainer;

import java.util.*;

/**
 * @author wxl
 */
@Configuration
public class ShareConsumerConfig {

    private static final Logger log = LoggerFactory.getLogger(ShareConsumerConfig.class);

    @Bean
    public ShareConsumerFactory<String, String> shareConsumerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
                StringDeserializer.class);
        return new DefaultShareConsumerFactory<>(props);
    }

    @Bean
    public ShareKafkaListenerContainerFactory<String, String> shareKafkaListenerContainerFactory(
            ShareConsumerFactory<String, String> shareConsumerFactory) {
        ShareKafkaListenerContainerFactory<String, String> factory = new ShareKafkaListenerContainerFactory<>(shareConsumerFactory);
        factory.setConcurrency(10); // 10 concurrent consumer threads
        return factory;
    }

    @Bean
    public ShareKafkaMessageListenerContainer<String, String> imageProcessingContainer(
            ShareConsumerFactory<String, String> shareConsumerFactory) {

        ContainerProperties containerProps = new ContainerProperties("image-processing");
        containerProps.setGroupId("image-processors");

        ShareKafkaMessageListenerContainer<String, String> container =
                new ShareKafkaMessageListenerContainer<>(shareConsumerFactory, containerProps);

        container.setupMessageListener(new MessageListener<String, String>() {
            @Override
            public void onMessage(ConsumerRecord<String, String> record) {
                int partition = record.partition();
                log.info("Processing image: {} partition: {}", record.value(), partition);
                // Implicit ACCEPT when method completes successfully
            }
        });

        return container;
    }

    @Bean
    public CommandLineRunner commandLineRunner(KafkaTemplate<String, String> template) {
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                new Timer().schedule(new TimerTask() {
                    @Override
                    public void run() {
                        template.send("image-processing", UUID.randomUUID().toString(), "image-2-" + UUID.randomUUID().toString());
                    }
                }, 3000, 1000);
            }
        };
    }
}

参考

相关推荐
香芋Yu8 小时前
【大模型教程——第二部分:Transformer架构揭秘】第2章:模型家族谱系:从编码器到解码器 (Model Architectures)
深度学习·架构·transformer
好好研究8 小时前
Spring Boot - Thymeleaf模板引擎
java·spring boot·后端·thymeleaf
爬山算法8 小时前
Hibernate(76)如何在混合持久化环境中使用Hibernate?
java·后端·hibernate
她说..9 小时前
策略模式+工厂模式实现单接口适配多审核节点
java·spring boot·后端·spring·简单工厂模式·策略模式
csdn_aspnet9 小时前
ASP.NET 8 - Cookie 身份验证
后端·asp.net·cookie·.net8
笔画人生9 小时前
Cursor + 蓝耘API:用自然语言完成全栈项目开发
前端·后端
从此不归路9 小时前
Qt5 进阶【13】桌面 Qt 项目架构设计:从 MVC/MVVM 到模块划分
开发语言·c++·qt·架构·mvc
java干货9 小时前
微服务:把一个简单的问题,拆成 100 个网络问题
网络·微服务·架构
有来技术10 小时前
ASP.NET Core 权限管理系统(RBAC)设计与实现|vue3-element-admin .NET 后端
vue.js·后端·c#·asp.net·.net
qq_124987075310 小时前
基于springboot的林业资源管理系统设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计