java中的Kafka使用者不消费消息

时间:2015-04-30 10:46:33

标签: java apache-kafka

我正在尝试向kafka消费者获取生成并发布到Java主题的消息。我的消费者如下。

consumer.java

        $needle= $_GET["singleid"];         
        $collection = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('name', array(
                array('like' => '% '.$needle.' %'), //spaces on each side
                array('like' => '% '.$needle), //space before and ends with $needle
                array('like' => $needle.' %') // starts with needle and space after
        ));
        $collection->addAttributeToSelect('name', 'entity_id', 'price');
        foreach ($collection as $_product){

            echo $_product->getId().'</br>';
            echo $_product->getName().'</br>';
            echo $_product->getProductUrl().'</br>';//getting this only
            echo $_product->getPrice().'</br>';

        }

当我运行上面的代码时,我在控制台中什么也得不到,因为屏幕后面的java生产者程序在“AATest”主题下不断发布数据。在zookeeper控制台中,当我尝试运行上面的consumer.java

时,我得到以下几行
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.javaapi.message.ByteBufferMessageSet;
import kafka.message.MessageAndOffset;



public class KafkaConsumer extends  Thread {
    final static String clientId = "SimpleConsumerDemoClient";
    final static String TOPIC = " AATest";
    ConsumerConnector consumerConnector;


    public static void main(String[] argv) throws UnsupportedEncodingException {
        KafkaConsumer KafkaConsumer = new KafkaConsumer();
        KafkaConsumer.start();
    }

    public KafkaConsumer(){
        Properties properties = new Properties();
        properties.put("zookeeper.connect","10.200.208.59:2181");
        properties.put("group.id","test-group");      
        ConsumerConfig consumerConfig = new ConsumerConfig(properties);
        consumerConnector = Consumer.createJavaConsumerConnector(consumerConfig);
    }

    @Override
    public void run() {
        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);
        System.out.println(stream);
        ConsumerIterator<byte[], byte[]> it = stream.iterator();
        while(it.hasNext())
            System.out.println("from it");
            System.out.println(new String(it.next().message()));

    }

    private static void printMessages(ByteBufferMessageSet messageSet) throws UnsupportedEncodingException {
        for(MessageAndOffset messageAndOffset: messageSet) {
            ByteBuffer payload = messageAndOffset.message().payload();
            byte[] bytes = new byte[payload.limit()];
            payload.get(bytes);
            System.out.println(new String(bytes, "UTF-8"));
        }
    }
}

当我运行一个指向AATest主题的单独控制台消费者时,我将生成器生成的所有数据都提供给该主题。

消费者和经纪人都在同一台机器上,而生产者在不同的机器上。这实际上类似于this question。但是通过它来帮助我。请帮帮我。

3 个答案:

答案 0 :(得分:1)

不同的答案,但在我的情况下恰好是消费者的初始偏移量(auto.offset.reset)。因此,设置auto.offset.reset=earliest修复了我的方案中的问题。这是因为我首先发布事件然后开始消费者。

默认情况下,消费者仅使用在启动后发布的事件,因为默认情况下为auto.offset.reset=latest

例如。 consumer.properties

bootstrap.servers=localhost:9092
enable.auto.commit=true
auto.commit.interval.ms=1000
session.timeout.ms=30000
auto.offset.reset=earliest
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.apache.kafka.common.serialization.StringDeserializer

测试

class KafkaEventConsumerSpecs extends FunSuite {

  case class TestEvent(eventOffset: Long, hashValue: Long, created: Date, testField: String) extends BaseEvent

  test("given an event in the event-store, consumes an event") {

    EmbeddedKafka.start()

    //PRODUCE
    val event = TestEvent(0l, 0l, new Date(), "data")
    val config = new Properties() {
      {
        load(this.getClass.getResourceAsStream("/producer.properties"))
      }
    }
    val producer = new KafkaProducer[String, String](config)

    val persistedEvent = producer.send(new ProducerRecord(event.getClass.getSimpleName, event.toString))

    assert(persistedEvent.get().offset() == 0)
    assert(persistedEvent.get().checksum() != 0)

    //CONSUME
    val consumerConfig = new Properties() {
      {
        load(this.getClass.getResourceAsStream("/consumer.properties"))
        put("group.id", "consumers_testEventsGroup")
        put("client.id", "testEventConsumer")
      }
    }

    assert(consumerConfig.getProperty("group.id") == "consumers_testEventsGroup")

    val kafkaConsumer = new KafkaConsumer[String, String](consumerConfig)

    assert(kafkaConsumer.listTopics().asScala.map(_._1).toList == List("TestEvent"))

    kafkaConsumer.subscribe(Collections.singletonList("TestEvent"))

    val events = kafkaConsumer.poll(1000)
    assert(events.count() == 1)

    EmbeddedKafka.stop()
  }
}

但是,如果首先启动消费者然后发布消费者,则消费者应该能够使用不需要将auto.offset.reset设置为earliest的事件。

参考kafka 0.10

https://kafka.apache.org/documentation/#consumerconfigs

答案 1 :(得分:1)

在我们的案例中,我们通过以下步骤解决了我们的问题:

我们发现的第一件事就是有一个名为“重试”的配置。对于KafkaProducer及其默认值意味着“没有重试”。此外,KafkaProducer的send方法是异步的,而不调用send方法的get方法的结果。这样,无法保证将生成的消息传递给相应的代理而不重试。所以,你必须增加一点,或者可以使用KafkaProducer的幂等或事务模式。

第二个案例是关于Kafka和Zookeeper的版本。我们选择了1.0.0版本的Kafka和Zookeeper 3.4.4。特别是,Kafka 1.0.0存在与Zookeeper连接的问题。如果Kafka在与意外的异常情况下失去与Zookeeper的连接,它将失去尚未同步的分区的领导权。有关此问题的错误主题: https://issues.apache.org/jira/browse/KAFKA-2729 在我们在Kafka日志中找到相应的日志后,我们将Kafka代理版本升级到1.1.0。

同样重要的是要注意小尺寸的分区(如100或更少)会增加生产者的吞吐量,因此如果没有足够的消费者,那么可用的消费者就会陷入延迟消息的结果中。我们用分钟测量延迟,大约10-15分钟)。因此,您需要根据可用资源正确平衡和配置应用程序的分区大小和线程数。

答案 2 :(得分:0)

在将新使用者添加到相同的组ID时,kafka可能还会花费很长时间重新平衡使用者组。 检查kafka日志以查看启动消费者后组是否重新平衡