使用kafka consumer high-level API開發的一些問題

Kafka的consumer是以pull的形式獲取消息數據的,consumer提供兩種版本,即high level 和low level API。

1 consumer和partition

1)如果consumer比partition多,是浪費,因爲kafka的設計是在一個partition上是不允許併發的,所以consumer數不要大於partition數
2)如果consumer比partition少,一個consumer會對應於多個partitions,這裏主要合理分配consumer數和partition數,否則會導致partition裏面的數據被取的不均勻,最好partiton數目是consumer數目的整數倍,所以partition數目很重要,比如取24,就很容易設定consumer數目
3)如果consumer從多個partition讀到數據,不保證數據間的順序性,kafka只保證在一個partition上數據是有序的,但多個partition,根據你讀的順序會有不同
4)增減consumer,broker,partition會導致rebalance,所以rebalance後consumer對應的partition會發生變化
5)High-level接口中獲取不到數據的時候是會block的。
6)突然停止Consumer以及Broker會導致消息重複讀的情況,爲了避免這種情況在shutdown之前通過Thread.sleep(10000)讓Consumer有時間將offset同步到zookeeper

2 關於auto.offset.reset的一些問題

如下所示爲kafkaconsumer的測試代碼:

public class kafkaConsumer extends Thread{

    private String topic;  

    public kafkaConsumer(String topic){  
        super();  
        this.topic = topic;  
    }  


    @Override  
    public void run() {  
        ConsumerConnector consumer = createConsumer();  
        Map<String, Integer> topicCountMap = new HashMap<String, Integer>();  
        topicCountMap.put(topic, 1); // 一次從主題中獲取一個數據  
         Map<String, List<KafkaStream<byte[], byte[]>>>  messageStreams = consumer.createMessageStreams(topicCountMap);  
         KafkaStream<byte[], byte[]> stream = messageStreams.get(topic).get(0);// 獲取每次接收到的這個數據  
         ConsumerIterator<byte[], byte[]> iterator =  stream.iterator();  
         while(iterator.hasNext()){  
             String message = new String(iterator.next().message());  
             System.out.println("接收到: " + message);  
         }  
    }  

    private ConsumerConnector createConsumer() {  
        Properties properties = new Properties();  
        properties.put("zookeeper.connect", "ip1:2181,ip2:2181,ip3:2181");//聲明zk  
        properties.put("group.id", "group03");
        return Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));  
     }  


    public static void main(String[] args) {  
        new kafkaConsumer("user").start();// 使用kafka集羣中創建好的topic:user      
    }  
}

auto.offset.reset 默認值爲largest,那麼auto.offset.reset 有什麼作用呢?auto.offset.reset定義了Consumer在ZooKeeper中發現沒有初始的offset時或者發現offset非法時定義Comsumer的行爲,常見的配置有:

  1. smallest : 自動把offset設爲最小的offset;
  2. largest : 自動把offset設爲最大的offset;
  3. anything else: 拋出異常;

遇到過這種情況:先produce一些數據,然後停止produce數據的線程——〉然後再用consumer上面的代碼消費數據,發現無數據可消費

其原因在於:初始的offset默認是非法的,而auto.offset.reset 默認值爲largest,表示自動把offset設爲最大的offset,由於此時沒有生產者向kafka push數據,當然沒有數據可以消費了。如果此時有生產者向kafka push數據,那麼該代碼可以從最新位置消費數據。

如果在代碼中增加如下配置:

properties.put("auto.offset.reset", "smallest"); 

那麼在停止生產者線程之後,再啓動消費者線程可以消費之前produce的數據。

3 high-level的Consumer工具

3.1 kafka.tools.ConsumerOffsetChecker
使用如下命令查看當前group的offset情況

 ./kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --group group03

這裏寫圖片描述

或者指定topic

./kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --topic user01 --group group03

如上圖所示pid表示topic的partition號,上圖中topic爲user0的partiton數量爲10;現在只啓動生產者線程一段時間後,再次運行上面的命令,發現如下:

這裏寫圖片描述

3.2 kafka.tools.UpdateOffsetsInZK

./kafka-run-class.sh kafka.tools.UpdateOffsetsInZK earliest config/consumer.properties  user01

該命令的三個參數
[earliest | latest],表示將offset置到哪裏
consumer.properties ,這裏是配置文件的路徑
topic,topic名,這裏是user01

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章