Kafka Kraft部署以及一些常见场景问题

1. 上单机DEMO

yaml 复制代码
version: "2"

services:
  kafka:
    image: docker.io/bitnami/kafka:3.6
    ports:
      - "9092:9092"
    volumes:
      - "kafka_data:/bitnami"
    environment:
      # KRaft settings
      - KAFKA_CFG_NODE_ID=0
      - KAFKA_CFG_PROCESS_ROLES=controller,broker
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
      # Listeners
      - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.0.102:9092
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT
  kafka-ui:
    image: 'provectuslabs/kafka-ui'
    ports: 
      - '9099:8080'
    environment:
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:9092
      - DYNAMIC_CONFIG_ENABLED=true
    depends_on:
      - kafka
volumes:
  kafka_data:
    driver: local

以上是从bitnami官方文档中截取出来的,解释下参数:

  • KAFKA_CFG_NODE_ID=0: 指定 Kafka broker 的节点 ID。每个 Kafka broker 都有一个唯一的节点 ID。

  • KAFKA_CFG_PROCESS_ROLES=controller,broker: 指定 Kafka broker 的角色。可选值broker controller broker,controller

    • broker: 数据复制、处理producer、consumer请求

    • controller: 负责集群的管理和协调,分区相关。

    • 设置为controller,broker表示这个节点负责数据相关,同时可以成为controller,但并不一定!

  • KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093: 负责选举的controller节点。格式:{node_id}@{node_host:port}

  • KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093: 定义 Kafka broker 监听客户端连接的网络地址。在这里,broker 听取 9092 端口上的 PLAINTEXT 协议连接,而 CONTROLLER 听取 9093 端口上的连接。PLAINTEXT和CONTROLLER仅仅表示协议

  • KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://192.168.0.102:9092: 定义 Kafka broker 对外宣传的监听地址。在这里,broker 在 192.168.0.102 地址的 9092 端口上 PLAINTEXT 协议连接。

    • 有些文章写 XXX://0.0.0.0:xx 表示可以被任意外部网络访问,但在 3.6版本测试报错不允许使用0.0.0.0,故必须配置为宿主机IP
  • KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT: 定义 Kafka broker 监听器之间的安全协议映射。在这里,将 CONTROLLER 监听器映射到 PLAINTEXT 协议,将 PLAINTEXT 监听器映射到 PLAINTEXT 协议。

    • 协议可选值:PLAINTEXTSSLSASL_PLAINTEXTSASL_SSL
  • KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER: 指定 Kafka controller 监听器的名称。

  • KAFKA_CFG_INTER_BROKER_LISTENER_NAME=PLAINTEXT: 定义 broker 之间通信所使用的监听器的名称。在这里,broker 之间使用 PLAINTEXT listener 进行通信。

2. 再搞搞 Kraft 集群

3 Broker + 每个Topic 3个Partition + 每个 Partition 两个副本 (1leader+2foller)

yaml 复制代码
version: '3'
services:
  kafka-0:
    image: bitnami/kafka:latest
    container_name: kafka-0
    networks:
      - kafka-network
    environment:
      - KAFKA_KRAFT_CLUSTER_ID=abcdefghijklmnopqrstuv
      - KAFKA_CFG_NODE_ID=0
      - KAFKA_CFG_PROCESS_ROLES=controller,broker
      - KAFKA_CFG_LISTENERS=BROKER://:9092,CONTROLLER://:9093
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,BROKER:PLAINTEXT
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=BROKER
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka-0:9093,1@kafka-1:9093,2@kafka-2:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=BROKER://192.168.0.102:9092

      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=3
      - KAFKA_CFG_DEFAULT_REPLICATION_FACTOR=3
      - KAFKA_CFG_NUM_PARTITIONS=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2

    ports:
      - "9092:9092"

  kafka-1:
    image: bitnami/kafka:latest
    container_name: kafka-1
    networks:
      - kafka-network
    environment:
      - KAFKA_KRAFT_CLUSTER_ID=abcdefghijklmnopqrstuv
      - KAFKA_CFG_NODE_ID=1
      - KAFKA_CFG_PROCESS_ROLES=controller,broker
      - KAFKA_CFG_LISTENERS=BROKER://:9092,CONTROLLER://:9093
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,BROKER:PLAINTEXT
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=BROKER
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka-0:9093,1@kafka-1:9093,2@kafka-2:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=BROKER://192.168.0.102:9093

      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=3
      - KAFKA_CFG_DEFAULT_REPLICATION_FACTOR=3
      - KAFKA_CFG_NUM_PARTITIONS=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2

    ports:
      - "9093:9092"


  kafka-2:
    image: bitnami/kafka:latest
    container_name: kafka-2
    networks:
      - kafka-network
    environment:
      - KAFKA_KRAFT_CLUSTER_ID=abcdefghijklmnopqrstuv
      - KAFKA_CFG_NODE_ID=2
      - KAFKA_CFG_PROCESS_ROLES=controller,broker
      - KAFKA_CFG_LISTENERS=BROKER://:9092,CONTROLLER://:9093
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=BROKER
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,BROKER:PLAINTEXT
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka-0:9093,1@kafka-1:9093,2@kafka-2:9093
      - KAFKA_CFG_ADVERTISED_LISTENERS=BROKER://192.168.0.102:9094

      - KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=3
      - KAFKA_CFG_DEFAULT_REPLICATION_FACTOR=3
      - KAFKA_CFG_NUM_PARTITIONS=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=3
      - KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2
    ports:
      - "9094:9092"
  kafka-ui:
    image: 'provectuslabs/kafka-ui'
    container_name: kafka-ui
    ports: 
      - '9099:8080'
    environment:
      - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka-0:9092,kafka-1:9092,kafka-2:9092
      - DYNAMIC_CONFIG_ENABLED=true
    networks:
      - kafka-network
    depends_on:
      - kafka-0
      - kafka-1
      - kafka-2
networks:
  kafka-network:

上面把PLAINTEXT改为了BROKER,更语义化一些。解释下新出现的参数:

  • KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR=3

    • 这个参数指定了偏移量主题(_consumer_offsets ,默认带的主题)的复制因子。偏移量主题用于存储消费者组的消费进度信息,确保在发生故障时不会丢失消费者的进度。复制因子指定了此主题的副本数量,这里设置为3,表示偏移量主题将有3个副本。
  • KAFKA_CFG_DEFAULT_REPLICATION_FACTOR=3

    • 这个参数指定了Kafka中新创建主题的默认复制因子。当创建一个新的主题而没有显式地指定复制因子时,系统将会使用此默认值。在这里,设置为3,表示新创建的主题将会有3个副本。
  • KAFKA_CFG_NUM_PARTITIONS=3

    • 这个参数指定了每个主题的分区数。主题被分割成多个分区,以便实现并行处理和水平扩展。在这里,设置为3,表示每个新创建的主题将会有3个分区。
  • KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=3

    • 这个参数指定了事务状态日志(transaction state log)的复制因子。事务状态日志用于存储Kafka事务的状态信息,确保在发生故障时不会丢失事务的状态。复制因子指定了此日志的副本数量,这里设置为3,表示事务状态日志将有3个副本。
  • KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR=2

    • 这个参数指定了事务状态日志的最小ISR(in-sync replicas)数。ISR是指能够跟上 leader 副本进度的副本集合。这个参数指定了 ISR 中必须包含的最少副本数量。在这里,设置为2,表示事务状态日志的最小ISR数量为2个。

最后,关于每个topic分区数的问题:引用佬的回答:一般来说如果有3个broker,那么至少就应该有3个分区,最小化保证每个broker都能参与到队列分流并行过程中。不过根据数据量的写入量,磁盘io的消耗占比,网络带宽的承载能力,我们可以适当增加每个broker的分区数,可以用每台broker分区最小数的倍数进行设置并测试吞吐,例如3,6,9,12...

3. 场景问题

3.1 顺序消息

一句话:生产者定key,消费者可以concurrency,可以batch拉取,但不要batch拉取后代码内批处理

3.2 消息不丢

生产者->Kafka服务端-> 消费者,箭头位置是消息可能丢失的地方,其余地方丢失几率不大或者不能叫做消息丢失

yaml 复制代码
# 修改三个地方
spring:
  kafka:
    bootstrap-servers: xxx
    producer:
      acks: 1 # 0,1,-1/all # !
      retries: 2 # 发送失败后重试两次 # !
    listener:
      ack-mode: manual_immediate  # 手动确认 !
    consumer:

解释:

  • producer.acks: 生产者到Kafka服务器的确认策略
    • 0:生产者在发出消息后不会等待任何来自服务器的确认。
    • 1:仅leader写入成功后,发回确认
    • -1/all:ISR所有元素成功写入则发回确认
  • listener.ack-mode: 消费端手动确认

3.3 重复消息

一句话:kafka自带精确一次消费太大,我用业务端去保证(如数据库唯一键)

3.4 消息积压

定问题,加机器!

3.5 事务消息

kotlin 复制代码
@Component
class KafkaProducer {
    @Bean
    fun txTemplate(default: DefaultKafkaProducerFactory<String, String>): KafkaTemplate<String, String> {
      	// 事务消息必须设置以下两个参数!覆盖一下默认配置
        val map = mapOf(Pair("acks", "all"), Pair(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "tx_"))
        val copy = default.copyWithConfigurationOverride(map)
        return KafkaTemplate(copy)
    }

    @Bean
    fun nonTxTemplate(default: DefaultKafkaProducerFactory<String, String>): KafkaTemplate<String, String> {
        // val map = mapOf(Pair("acks", "1")) // 不设置也可以,配置文件就是默认配置
        val copy = default.copyWithConfigurationOverride(map)
        return KafkaTemplate(copy)
    }
}
yaml 复制代码
spring:
  kafka:
    bootstrap-servers: 127.0.0.1:9092
    producer:
      batch-size: 16KB
      properties:
        linger.ms: 500 # 最长等待发送时间
      acks: 1 # 0,1,-1/all
      retries: 2 # 发送失败后重试两次
    listener:
      ack-mode: batch  # 自动提交
      concurrency: 10
    consumer:
      isolation-level: read_committed  # 确保事务消息不会脏读

参考资料

相关推荐
中烟创新17 分钟前
DeepSeek部署实战:模型对比、部署优化与应用场景解析
前端·后端
亚洲第一中锋_哈达迪1 小时前
详解缓存淘汰策略:LFU
后端·缓存·golang
灰小猿1 小时前
多级@JsonTypeInfo和@JsonSubTypes注解使用详解及场景分析
java·后端·mysql·spring·spring cloud
子林super1 小时前
PostgreSQL主从切换后时间线修复操作手册
后端
程序员鱼皮1 小时前
Stack Overflow,彻底凉了!
前端·后端·计算机·程序员·互联网
neoooo1 小时前
Spring Boot 中的 synchronized(this):到底锁住了谁?
java·spring boot·后端
京东云开发者1 小时前
基于业务知识和代码库增强的大模型生成代码实践
后端
贵州数擎科技有限公司2 小时前
LangChain 快速构建你的第一个 LLM 应用
前端·后端
小王的饲养员2 小时前
Apipost 与 Apifox 数据库功能对比:深入解析与应用场景分析
大数据·数据库·人工智能·后端·postman
白仑色2 小时前
Spring Boot 安全登录系统:前后端分离实现
spring boot·后端·安全