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  # 确保事务消息不会脏读

参考资料

相关推荐
炒空心菜菜1 小时前
MapReduce 实现 WordCount
java·开发语言·ide·后端·spark·eclipse·mapreduce
wowocpp3 小时前
spring boot Controller 和 RestController 的区别
java·spring boot·后端
后青春期的诗go3 小时前
基于Rust语言的Rocket框架和Sqlx库开发WebAPI项目记录(二)
开发语言·后端·rust·rocket框架
freellf3 小时前
go语言学习进阶
后端·学习·golang
全栈派森5 小时前
云存储最佳实践
后端·python·程序人生·flask
CircleMouse5 小时前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
獨枭6 小时前
使用 163 邮箱实现 Spring Boot 邮箱验证码登录
java·spring boot·后端
维基框架6 小时前
Spring Boot 封装 MinIO 工具
java·spring boot·后端
秋野酱6 小时前
基于javaweb的SpringBoot酒店管理系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
☞无能盖世♛逞何英雄☜7 小时前
Flask框架搭建
后端·python·flask