我需要在晚上执行一个Job,它将获取kafka队列中的所有消息并使用它们执行一个进程。我能够收到消息,但是kafka流正在等待更多消息,我无法继续我的进程。我有以下代码:
...
private ConsumerConnector consumerConnector;
private final static String TOPIC = "test";
public MessageStreamConsumer() {
Properties properties = new Properties();
properties.put("zookeeper.connect", "localhost:2181");
properties.put("group.id", "test-group");
ConsumerConfig consumerConfig = new ConsumerConfig(properties);
consumerConnector = Consumer.createJavaConsumerConnector(consumerConfig);
}
public List<String> getMessages() {
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(TOPIC, new Integer(1));
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumerConnector
.createMessageStreams(topicCountMap);
KafkaStream<byte[], byte[]> stream = consumerMap.get(TOPIC).get(0);
ConsumerIterator<byte[], byte[]> it = stream.iterator();
List<String> messages = new ArrayList<>();
while (it.hasNext())
messages.add(new String(it.next().message()));
return messages;
}
代码能够获取消息,但是当它处理最后一条消息时,它仍然保留在行中:
while (it.hasNext())
问题是,如何从kafka获取所有消息,停止流并继续执行其他任务。
我希望你能帮助我
由于
答案 0 :(得分:0)
似乎kafka流不支持从头开始消费
你可以创建一个本地kafka消费者并将auto.offset.reset
设置为最早,然后它将从开始消费消息。
答案 1 :(得分:0)
这样的事可能有用。基本上我的想法是使用Kafka消费者和民意调查,直到你得到一些记录,然后当你得到一个空的批次时停止。
package kafka.examples;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
public class Consumer1 extends Thread
{
private final KafkaConsumer<Integer, String> consumer;
private final String topic;
private final DateFormat df;
private final String logTag;
private boolean noMoreData = false;
private boolean gotData = false;
private int messagesReceived = 0;
AtomicBoolean isRunning = new AtomicBoolean(true);
CountDownLatch shutdownLatch = new CountDownLatch(1);
public Consumer1(Properties props)
{
logTag = "Consumer1";
consumer = new KafkaConsumer<>(props);
this.topic = props.getProperty("topic");
this.df = new SimpleDateFormat("HH:mm:ss");
consumer.subscribe(Collections.singletonList(this.topic));
}
public void getMessages() {
System.out.println("Getting messages...");
while (noMoreData == false) {
//System.out.println(logTag + ": Doing work...");
ConsumerRecords<Integer, String> records = consumer.poll(1000);
Date now = Calendar.getInstance().getTime();
int recordsCount = records.count();
messagesReceived += recordsCount;
System.out.println("recordsCount: " + recordsCount);
if (recordsCount > 0) {
gotData = true;
}
if (gotData && recordsCount == 0) {
noMoreData = true;
}
for (ConsumerRecord<Integer, String> record : records) {
int kafkaKey = record.key();
String kafkaValue = record.value();
System.out.println(this.df.format(now) + " " + logTag + ":" +
" Received: {" + kafkaKey + ":" + kafkaValue + "}" +
", partition(" + record.partition() + ")" +
", offset(" + record.offset() + ")");
}
}
System.out.println("Received " + messagesReceived + " messages");
}
public void processMessages() {
System.out.println("Processing messages...");
}
public void run() {
getMessages();
processMessages();
}
}
答案 2 :(得分:0)
我目前正在使用Kafka 0.10.0.1进行开发,并发现有关使用消费者属性 auto.offset.reset 的混合信息,所以我做了一些实验来弄清楚究竟发生了什么。< / p>
基于这些,我现在就这样理解了:当你设置属性时:
auto.offset.reset=earliest
这将消费者定位为分配的分区中的第一个可用消息(当没有对分区进行提交时)或者将消费者定位在最后提交的分区偏移量(请注意,您始终提交最后一个读取偏移量+ 1否则你将在每次重启消费者时重新阅读最后提交的消息)
或者,您不要设置 auto.offset.reset ,这意味着将使用默认值'latest'。
在这种情况下,您不会收到任何关于连接消费者的旧消息 - 只有在连接消费者后才会发布到该主题的消息。
作为结论 - 如果您想确保接收特定主题和分配的分区的所有可用消息,则必须调用seekToBeginning()。
似乎建议首先调用poll(0L)以确保您的使用者获得分配的分区(或在ConsumerRebalanceListener中实现您的代码!),然后将每个分配的分区寻找为“开始”:
kafkaConsumer.poll(0L);
kafkaConsumer.seekToBeginning(kafkaConsumer.assignment());