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

参考资料

相关推荐
笃行3502 小时前
从零开始:SpringBoot + MyBatis + KingbaseES 实现CRUD操作(超详细入门指南)
后端
该用户已不存在2 小时前
这几款Rust工具,开发体验直线上升
前端·后端·rust
用户8356290780512 小时前
C# 从 PDF 提取图片教程
后端·c#
L2ncE2 小时前
高并发场景数据与一致性的简单思考
java·后端·架构
水涵幽树3 小时前
MySQL 时间筛选避坑指南:为什么格式化字符串比较会出错?
数据库·后端·sql·mysql·database
ERP老兵_冷溪虎山3 小时前
从ASCII到Unicode:"国际正则"|"表达式"跨国界实战指南(附四大语言支持对比+中医HIS类比映射表)
后端·面试
HyggeBest3 小时前
Golang 并发原语 Sync Cond
后端·架构·go
老张聊数据集成3 小时前
数据建模怎么做?一文讲清数据建模全流程
后端
颜如玉3 小时前
Kernel bypass技术遥望
后端·性能优化·操作系统
一块plus4 小时前
创造 Solidity、提出 Web3 的他回来了!Gavin Wood 这次将带领波卡走向何处?
javascript·后端·面试