背景

多台机器生成事件。 这些事件将发送到我们的Kafka集群,其中每台机器都有自己的主题(app.machine-events。machine -name )。 因为顺序对于每台计算机而言很重要,并且分区大小现在不是问题,所以所有主题都由一个分区组成。 因此,当前N个主题也意味着N个分区。

消费/处理应用程序利用kafka-streams,我们为它提供了StreamsConfig.APPLICATION_ID_CONFIG / "application.id" 'machine-event-processor',对于每个实例它都保持不变,这意味着它们被放入同一实例中卡夫卡的消费群体。 该使用者已订阅模式app.machine-events.* ,因为对于处理器,它处理的是哪个机器的事件都没有关系。 这已经通过./kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group machine-event-processor --members --verbose显示了一个与所有IP数量匹配的列表处理服务正在运行。

预期

给定20台计算机和5个处理器实例,我们希望每个处理器处理约4个分区(因此约有4个主题)。

其实

有一个处理器处理20个分区(因此有20个主题),而其他4个处理器则完全不执行任何操作/空闲。 杀死“幸运”处理器后,所有20个分区都重新平衡到另一个处理器,导致新处理器处理20个分区/主题,并使3个处理器空闲。

到目前为止我尝试过的

  • 检出partition.grouper 我觉得我不太了解,但是据我所知,仍然只有DefaultPartitioner选项,并且(根据文档)不必编写自定义选项,因为此设置可以正常工作。 它确实提到了分区是基于分区键(对于我们来说都是0,因为每个主题只有一个分区)加入到任务中,但是我无法完全理解这一部分。
  • 供使用者使用的RoundRobinAssignor: settings.put(StreamsConfig.consumerPrefix(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG), new RoundRobinAssignor().getClass.getName) (尝试了多个值,因为似乎没有什么变化。)
  • 查看其他配置属性 ,以查看是否遗漏了一些东西:我认为没有。

代码,简化

val streamConfig = new Properties
// {producer.metadata.max.age.ms=5000, consumer.metadata.max.age.ms=5000, default.key.serde=org.apache.kafka.common.serialization.Serdes$StringSerde, consumer.partition.assignment.strategy=org.apache.kafka.clients.consumer.RoundRobinAssignor, bootstrap.servers=kafka:9092, application.id=machine-event-processor, default.value.serde=org.apache.kafka.common.serialization.Serdes$ByteArraySerde}
val builder: StreamsBuilder = new StreamsBuilder
val topicStream: KStream[String, Array[Byte]] = builder.stream(Pattern.compile("app.machine-events.*"))
topicStream.process(new MessageProcessorSupplier(context)) // The event is delegated to a processor, doing the actual processing logic
val eventStreams = new KafkaStreams(builder.build(), streamConfig)
eventStreams.start()

笔记

  • 使用Kafka-streams 2.0.0:

    <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-streams</artifactId> <version>2.0.0</version> </dependency>

  • Kafka正在使用wurstmeister/kafka:2.11-2.0.0版本在容器内运行。 docker-stack.yml服务:

kafka: image: wurstmeister/kafka:2.11-2.0.0 ports: - target: 9094 published: 9094 protocol: tcp mode: host volumes: - /var/run/docker.sock:/var/run/docker.sock healthcheck: test: ["CMD-SHELL", "$$(netstat -ltn | grep -q 9092)"] interval: 15s timeout: 10s retries: 5 environment: HOSTNAME_COMMAND: "docker info | grep ^Name: | cut -d' ' -f 2" KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS: 36000 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT KAFKA_ADVERTISED_LISTENERS: INSIDE://:9092,OUTSIDE://_{HOSTNAME_COMMAND}:9094 KAFKA_LISTENERS: INSIDE://:9092,OUTSIDE://:9094 KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE KAFKA_DEFAULT_REPLICATION_FACTOR: 2 deploy: replicas: 2 restart_policy: condition: on-failure delay: 5s max_attempts: 3 window: 120s

  • Kafka是在双节点设置中设置的,形成一个集群。 通过docker环境变量,我们将复制因子设置为2 ,因此每个分区应该在每个节点上都有一个复制。

我找到并检查过的相关主题/问题/讨论

如果有人遇到类似问题,或者能够指出我可能非常愚蠢的错误,请赐教!

#1楼 票数:0 已采纳

对于将来遇到此问题的读者,解决方案是不使用每个都有1个分区的N个主题,而使用带有N个分区的1个主题。 即使有120个分区和400多个计算机/事件源,也将多个事件类型放入同一个分区,但这不会影响事件的顺序。

实现是将记录键设置为计算机名称,并让底层逻辑负责将哪个值分配给哪个分区。 由于我们现在有一个消费者组,其中有X个消费者订阅了该主题,因此分区在消费者上平均分配,每个分区有120 / X个分区。

正如Matthias所建议的那样,Confluent的其他乐于助人的人在Devoxx Belgium 2018上进一步证实了这一点。谢谢!

小费

使用wurstmeister / kafka docker映像时,请考虑使用environment属性:

KAFKA_CREATE_TOPICS:“ app.machine-events:120:2”

含义

主题名称:数的-分区:复制因子

  ask by Forvaine translate from so

未解决问题?本站智能推荐:

2回复

将 kafka-streams 与自定义分区器一起使用

我想加入带有 KTable 的 KStream。 两者都有不同的键,但使用自定义分区器共同分区。 但是,连接不会产生和结果。 KStream具有以下结构 - 关键:房子 - 组 - 值:用户 KTable具有以下结构 - 键:用户 - 组 - 值:地址 为了确保每个插入的主题都按插入顺序处理,我
1回复

为同一应用程序中的不同使用者分配不同的组ID

我知道kafka流提供的并行性优势,如果您的并行性需求与主题划分保持一致,就会利用这些优势。 我正在考虑让一个应用程序将许多使用者订阅到不同的使用者组,以便每个使用者都在使用整个主题的副本。 具体来说,我正在考虑让多个线程使用同一主题来提供不同的结果,即使我知道我可以使用KStrea
1回复

如何使用 spring-kafka 和 kafka-streams 在 KStreams Bean 中记录偏移量

我已经提到了几乎所有关于通过处理器 API 的 transform() 或 process() 方法在 KStreams 上记录偏移量的问题,就像这里的许多问题中提到的一样 - 如何在 KStream 中获取偏移值 但我无法得到这些答案的解决方案,所以我问这个问题。 我想在每次流消耗消息时记录
1回复

使用 Kafka-Streams 进行重复数据删除

我想在使用状态存储的 kafka-streams 应用程序中进行重复数据删除,并使用这个非常好的示例: https://github.com/confluentinc/kafka-streams-examples/blob/5.5.0-post/src/test/java/io/confluen
1回复

终止使用 Kafka-Streams 和 MongoDB 的 Spring Boot 应用程序

我有一个使用 Kafka-Streams 的 Spring Boot 应用程序。 详细地说,有一个流使用在 MongoDB 中执行的查询的结果过滤它收到的消息。 该代码类似于以下内容。 方法service.hasSomeProperty(message)调用 Mongo 存储库,该存储库对专用集
1回复

Kafka-streams 中的 StreamPartitioner 是线程安全的吗?

我正在构建简单的 kafka-streams 应用程序。我需要使用多个线程和自定义 StreamPartitioner: 我可以确定不同的线程将使用它们自己的分区器实例吗? 如果没有,我该如何执行?
1回复

Kafka通过多个分区和多个使用者线程提高吞吐量

我在某些应用程序中使用kafka流。 流如下 我有生产者,它可以非常快速地写入数据,并且我的StreamConsumer会将每个流与某些进程映射,并将该流转发到其他主题。 在我的StreamCosumer映射中,我添加了自己的映射器函数,该函数实际上试图保留其相关数据,如下所
1回复

JSON对象的Kafka流使用者:如何映射

我是Kafka / Kafka Stream的新手。 我正在使用最新的 Kafka / kafka-stream和kafka-client和openjdk11 。 我的生产者正在生产看起来像的json对象(其中key是名称 ) 生产者代码以更好地理解: 现在,我正在尝试编写用