Apache Kafka – 关于主题/分区的KafkaStream

我正在为高容量高速分布式应用编写Kafka Consumer。 我只有一个主题,但传入消息的速率非常高。 拥有多个服务于更多消费者的分区将适用于此用例。 最好的消费方式是拥有多个流阅读器。 根据文档或可用示例,ConsumerConnector提供的KafkaStream数量基于主题数量。 想知道如何获得多个KafkaStream读取器[基于分区],以便我可以跨每个流跨越一个线程或从多个线程中的相同KafkaStream读取将从多个分区进行并发读取?

任何见解都非常感谢。

想分享我在邮件列表中找到的内容:

您在主题图中传递的数字控制主题分为多少个流。 在您的情况下,如果传入1,则所有10个分区的数据将被送入1个流。 如果传入2,则2个流中的每一个都将从5个分区获取数据。 如果传入11,其中10个将从1个分区获取数据,1个流将不会获得任何数据。

通常,您需要在自己的线程中迭代每个流。 这是因为如果没有新事件,每个流都可以永久阻止。

示例代码段:

topicCount.put(msgTopic, new Integer(partitionCount)); Map>> consumerStreams = connector.createMessageStreams(topicCount); List> streams = consumerStreams.get(msgTopic); for (final KafkaStream stream : streams) { ReadTask task = new ReadTask(stream, msgTopic); task.addObserver(this.msgObserver); tasks.add(task); executor.submit(task); } 

参考: http : //mail-archives.apache.org/mod_mbox/incubator-kafka-users/201201.mbox/%3CCA+sHyy_Z903dOmnjp7_yYR_aE2sRW-x7XpAnqkmWaP66GOqf6w@mail.gmail.com%3E

建议的方法是使用一个线程池,以便Java可以为您处理组织,并且对于每个流,createMessageStreamsByFilter方法允许您在Runnable中使用它。 例如:

 int NUMBER_OF_PARTITIONS = 6; Properties consumerConfig = new Properties(); consumerConfig.put("zk.connect", "zookeeper.mydomain.com:2181" ); consumerConfig.put("backoff.increment.ms", "100"); consumerConfig.put("autooffset.reset", "largest"); consumerConfig.put("groupid", "java-consumer-example"); consumer = Consumer.createJavaConsumerConnector(new ConsumerConfig(consumerConfig)); TopicFilter sourceTopicFilter = new Whitelist("mytopic|myothertopic"); List> streams = consumer.createMessageStreamsByFilter(sourceTopicFilter, NUMBER_OF_PARTITIONS); ExecutorService executor = Executors.newFixedThreadPool(streams.size()); for(final KafkaStream stream: streams){ executor.submit(new Runnable() { public void run() { for (MessageAndMetadata msgAndMetadata: stream) { ByteBuffer buffer = msgAndMetadata.message().payload(); byte [] bytes = new byte[buffer.remaining()]; buffer.get(bytes); //Do something with the bytes you just got off Kafka. } } }); } 

在这个例子中,我基本上要求6个线程,因为我知道每个主题有3个分区,我在白名单中列出了两个主题。 一旦我们获得了传入流的句柄,我们就可以迭代它们的内容,即MessageAndMetadata对象。 元数据实际上只是主题名称和偏移量。 正如您所发现的,如果您要求1个流而不是在我的示例6中,您可以在单个线程中执行此操作,但是如果您需要并行处理,那么很好的方法是为每个返回的流启动一个带有一个线程的执行程序。

 /** * @param source : source kStream to sink output-topic */ private static void pipe(KStream source) { source.to(Serdes.String(), Serdes.String(), new StreamPartitioner() { @Override public Integer partition(String arg0, String arg1, int arg2) { return 0; } }, "output-topic"); } 

上面的代码将在主题名称“output-topic”的分区1处写入记录