背景
多台机器会生成事件。这些事件将发送到我们的Kafka集群,其中每台机器都有自己的主题(app.machine-events。机器名称)。因为顺序对于每台计算机而言很重要,并且分区大小现在不是问题,所以所有主题都由一个分区组成。因此,当前N个主题也意味着N个分区。
消费/处理应用程序利用kafka流,我们为它们提供了StreamsConfig.APPLICATION_ID_CONFIG
/ "application.id"
'机器事件处理器',每个实例都保持不变,这意味着它们与卡夫卡同属一个消费群体。该使用者订阅了模式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个处理器空闲。
到目前为止我尝试过的事情
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
2
,因此每个分区在每个节点上都应该有一个复制。我找到并检查过的相关主题/问题/讨论
https://faust.readthedocs.io/en/latest/developerguide/partition_assignor.html
签出了Kafka mail archives,但在那里找不到任何内容
全方位搜索遇到此问题的其他人,但没有给我所需的答案。还发现了KAFKA-7144,但这对我们来说不是问题,因为我们正在运行2.0.0
如果有人遇到类似问题,或者能够指出我可能非常愚蠢的错误,请赐教!
答案 0 :(得分:0)
对于将来遇到相同问题的读者,解决方案是不使用每个都有1个分区的N个主题,而使用带有N个分区的1个主题。即使有120个分区和400多个机器/事件源,也将多个事件类型放入同一个分区,但这不会影响事件的顺序。
实现是将记录键设置为计算机名称,然后让底层逻辑负责将哪个值分配给哪个分区。由于我们现在有一个消费者组,其中有X个消费者订阅了该主题,因此将分区均匀地划分到各个消费者上,每个分区都有120 / X个分区。
正如Matthias所建议的那样,Confluent的其他乐于助人的人在Devoxx Belgium 2018上得到了进一步证实。谢谢!
提示
使用wurstmeister / kafka docker映像时,请考虑使用环境属性:
KAFKA_CREATE_TOPICS:“ app.machine-events:120:2”
含义
主题名称:分区数:复制因子