從kafka中自定義處開始獲取數據

@Author  : Spinach | GHB
@Link    : http://blog.csdn.net/bocai8058


三種情況的消費者不同使用方式下,消費者提交offset的情況進行了歸總和說明:

從開頭處獲取數據

配置設置

設置auto.offset.reset爲earliest或latest

默認是latest(消費者從最新的記錄開始讀取數據);
     earliest(消費者從起始位置讀取partition的記錄)

Kafka-SparkStreaming設置

val conf = new SparkConf().setMaster("local[4]").setAppName("TagGen");
val sc = new StreamingContext(conf, Seconds(15)); //5 minter
val kafkaParams = Map[String, Object](
            "bootstrap.servers" -> "10.1.3.5:6667",
            "key.deserializer" -> classOf[StringDeserializer],
            "value.deserializer" -> classOf[StringDeserializer],
            "group.id" -> "test-consumer-group",
            "auto.offset.reset" -> "earliest", //從分區末尾獲取數據,還可設置爲earliest(從分區頭獲取數據)
            "enable.auto.commit" -> (false: java.lang.Boolean))

val topics = Array("TagGen")

// 解決數據積壓問題
val stream = KafkaUtils.createDirectStream[String, String](
            sc,
            PreferConsistent,
            Subscribe[String, String](topics, kafkaParams)
            )
val sources = stream.map(e => e.value().toString) //e.value() 是kafka消息內容,e.key爲空值

代碼實現

/**
 * @author yujie.wang
 * kafka消費者示例,包含隨機位置消費和最多一次消費方式
 * 消費者提交消費數據offset 分爲自動提交和手動控制提交
 * 
 * 這份代碼示例中包含了 多種從kafka的任意位置獲取數據的方式
 */
public class Consumer_Sample {
 
	//kafka集羣機器
	private static final String KAFKA_HOSTS = "10.4.30.151:9092,10.4.30.151:9093,10.4.30.151:9094";
	//topic名稱
	private static final String TOPIC = "my-replicated-topic_2";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Consumer_Sample consumer = new Consumer_Sample();
		//從指定的分區  開始位置seekToBeginning 或者任意位置seek消費數據
		consumer.consumerAssin("true", TOPIC);
		
		
		
		System.out.println("consumer end");
	}
	
	
	/**
	 * 通過assign分配的分區,消費者發生故障 Server端不會觸發分區重平衡(即使該消費者共享某個已有的groupId),每個消費者都是獨立工作的
	 * 爲了避免offset提交衝突,需要確保每個消費者都有唯一的groupId
	 * 從指定的分區的開頭開始消費數據
	 * @param isAutoCommitBool true 開啓自動提交offset;false 不開啓
	 * @param topic
	 */
	public void consumerAssin(String isAutoCommitBool,String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie35");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //獲得topic的所有分區
		 List<PartitionInfo> parList = consumer.partitionsFor(topic);
		 //打印出分區信息
		 printPartition(parList);
		 
		 List<TopicPartition> list = new ArrayList<TopicPartition>();
		 for(PartitionInfo par : parList){
			 TopicPartition partition = new TopicPartition(topic, par.partition());
			 list.add(partition);
		 }
		 //消費者指定要消費的分區,指定分區之後消費者崩潰之後 不會引發分區reblance
	     consumer.assign(list);
 
    	 //從list中所有分區的開頭開始消費數據,這個操作不改變已提交的消費數據的offset
 	    // consumer.seekToBeginning(list);
	 
 
	 /*    for(TopicPartition tpar:list ){
	    	 //consumer.seek(tpar, position);
	     } */
     
 
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + " pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
}

從當前最新獲取數據

配置設置

設置auto.offset.reset爲earliest或latest

默認是latest(消費者從最新的記錄開始讀取數據);
     earliest(消費者從起始位置讀取partition的記錄)

Kafka-SparkStreaming設置

val conf = new SparkConf().setMaster("local[4]").setAppName("TagGen");
val sc = new StreamingContext(conf, Seconds(15)); //5 minter
val kafkaParams = Map[String, Object](
            "bootstrap.servers" -> "10.1.3.5:6667",
            "key.deserializer" -> classOf[StringDeserializer],
            "value.deserializer" -> classOf[StringDeserializer],
            "group.id" -> "test-consumer-group",
            "auto.offset.reset" -> "earliest", //從分區末尾獲取數據,還可設置爲earliest(從分區頭獲取數據)
            "enable.auto.commit" -> (false: java.lang.Boolean))

val topics = Array("TagGen")

// 解決數據積壓問題
val stream = KafkaUtils.createDirectStream[String, String](
            sc,
            PreferConsistent,
            Subscribe[String, String](topics, kafkaParams)
            )
val sources = stream.map(e => e.value().toString) //e.value() 是kafka消息內容,e.key爲空值

代碼實現

/**
 * @author yujie.wang
 * kafka消費者示例,包含隨機位置消費和最多一次消費方式
 * 消費者提交消費數據offset 分爲自動提交和手動控制提交
 * 
 * 這份代碼示例中包含了 多種從kafka的任意位置獲取數據的方式
 */
public class Consumer_Sample {
 
	//kafka集羣機器
	private static final String KAFKA_HOSTS = "10.4.30.151:9092,10.4.30.151:9093,10.4.30.151:9094";
	//topic名稱
	private static final String TOPIC = "my-replicated-topic_2";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Consumer_Sample consumer = new Consumer_Sample();
		//從分區的末尾 或者已存在groupid的請情況下從未消費位置開始消費數據
		consumer.consumerSubscribe("true", TOPIC);
				
		//通過配置屬性auto.offset.reset 來設置消費者從分區開頭或者末尾進行消費,但是需要使用一定條件的group Id
		consumer.consumerAutoOffsetReset("true", TOPIC);
		
		System.out.println("consumer end");
	}
	
	
	/**
	 * 直接通過訂閱一個指定分區來消費數據
	 * (1)如果該groupId消費者分組下 有消費者提交過offset,則從 當前提交的offset位置開始消費數據
	 * (2)如果該groupId消費者分組下 沒有有消費者提交過offset,則從 當前log添加的最後位置(也就是數據的末尾)開始消費數據
	 * @param isAutoCommitBool
	 * @param topic
	 */
	public void consumerSubscribe(final String isAutoCommitBool, final String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie37");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 final KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //訂閱topic
		 consumer.subscribe(Arrays.asList(topic));
		 List<PartitionInfo> parList = consumer.partitionsFor(topic);
 
		 //打印出分區信息
		 printPartition(parList);
 
		 //消費數據
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + " pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
	
	
	/**
	 * 
	 * @param isAutoCommitBool true 開啓自動提交offset;false 不開啓
	 * @param topic
	 * 如果groupId之前存在 , 則從之前提交的最後消費數據的offset處繼續開始消費數據
	 * 如果groupId之前不存在,則從當前分區的最後位置開始消費
	 * 
	 * 注意如果enable.auto.commit 設置爲false,如果消費完數據沒有提交已消費數據的offset,
	 * 則會出現重複消費數據的情況
	 */
	public void consumerAutoOffsetReset(final String isAutoCommitBool, final String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie32");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 //設置使用最開始的offset偏移量爲該group.id的最早。如果不設置,則會是latest即該topic最新一個消息的offset
	     //如果採用latest,消費者只能得道其啓動後,生產者生產的消息
		 //一般配置earliest 或者latest 值
	     props.put("auto.offset.reset", "latest");
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 final KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //訂閱topic,並實現ConsumerRebalanceListener
		 consumer.subscribe(Arrays.asList(topic));
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + "pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
 
	
	public void printPartition(List<PartitionInfo> parList){
		for(PartitionInfo p : parList){
			System.out.println(p.toString());
		}
	}
	
	/**
	 * 單獨處理每個分區中的數據,處理完了之後異步提交offset,注意提交的offset是程序將要讀取的下一條消息的offset
	 * @param consumer
	 */
	public void handlerData(KafkaConsumer<String, String> consumer){
		boolean running = true;
		try {
	         while(running) {
	             ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);
	             for (TopicPartition partition : records.partitions()) {
	                 List<ConsumerRecord<String, String>> partitionRecords = records.records(partition);
	                 for (ConsumerRecord<String, String> record : partitionRecords) {
	                     System.out.println(record.offset() + ": " + record.value());
	                 }
	                 long lastOffset = partitionRecords.get(partitionRecords.size() - 1).offset();
	                 //注意提交的offset是程序將要讀取的下一條消息的offset
	                 consumer.commitSync(Collections.singletonMap(partition, new OffsetAndMetadata(lastOffset + 1)));
	             }
	         }
	     } finally {
	       consumer.close();
	     }
	}
	
	
}

從上次斷開處獲取數據

代碼實現

/**
 * @author yujie.wang
 * kafka消費者示例,包含隨機位置消費和最多一次消費方式
 * 消費者提交消費數據offset 分爲自動提交和手動控制提交
 * 
 * 這份代碼示例中包含了 多種從kafka的任意位置獲取數據的方式
 */
public class Consumer_Sample {
 
	//kafka集羣機器
	private static final String KAFKA_HOSTS = "10.4.30.151:9092,10.4.30.151:9093,10.4.30.151:9094";
	//topic名稱
	private static final String TOPIC = "my-replicated-topic_2";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Consumer_Sample consumer = new Consumer_Sample();
		//從分區的末尾 或者已存在groupid的請情況下從未消費位置開始消費數據
		consumer.consumerSubscribe("true", TOPIC);
		System.out.println("consumer end");
	}
	
	
	/**
	 * 直接通過訂閱一個指定分區來消費數據
	 * (1)如果該groupId消費者分組下 有消費者提交過offset,則從 當前提交的offset位置開始消費數據
	 * (2)如果該groupId消費者分組下 沒有有消費者提交過offset,則從 當前log添加的最後位置(也就是數據的末尾)開始消費數據
	 * @param isAutoCommitBool
	 * @param topic
	 */
	public void consumerSubscribe(final String isAutoCommitBool, final String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie37");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 final KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //訂閱topic
		 consumer.subscribe(Arrays.asList(topic));
		 List<PartitionInfo> parList = consumer.partitionsFor(topic);
 
		 //打印出分區信息
		 printPartition(parList);
 
		 //消費數據
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + " pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
}

從指定offset處獲取數據

代碼實現

/**
 * @author yujie.wang
 * kafka消費者示例,包含隨機位置消費和最多一次消費方式
 * 消費者提交消費數據offset 分爲自動提交和手動控制提交
 * 
 * 這份代碼示例中包含了 多種從kafka的任意位置獲取數據的方式
 */
public class Consumer_Sample {
 
	//kafka集羣機器
	private static final String KAFKA_HOSTS = "10.4.30.151:9092,10.4.30.151:9093,10.4.30.151:9094";
	//topic名稱
	private static final String TOPIC = "my-replicated-topic_2";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Consumer_Sample consumer = new Consumer_Sample();
		//從指定的分區  開始位置seekToBeginning 或者任意位置seek消費數據
		consumer.consumerAssin("true", TOPIC);
		System.out.println("consumer end");
	}
	
	
	/**
	 * 通過assign分配的分區,消費者發生故障 Server端不會觸發分區重平衡(即使該消費者共享某個已有的groupId),每個消費者都是獨立工作的
	 * 爲了避免offset提交衝突,需要確保每個消費者都有唯一的groupId
	 * 從指定的分區的開頭開始消費數據
	 * @param isAutoCommitBool true 開啓自動提交offset;false 不開啓
	 * @param topic
	 */
	public void consumerAssin(String isAutoCommitBool,String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie35");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //獲得topic的所有分區
		 List<PartitionInfo> parList = consumer.partitionsFor(topic);
		 //打印出分區信息
		 printPartition(parList);
		 
		 List<TopicPartition> list = new ArrayList<TopicPartition>();
		 for(PartitionInfo par : parList){
			 TopicPartition partition = new TopicPartition(topic, par.partition());
			 list.add(partition);
		 }
		 //消費者指定要消費的分區,指定分區之後消費者崩潰之後 不會引發分區reblance
	     consumer.assign(list);
 
    	 //從list中所有分區的開頭開始消費數據,這個操作不改變已提交的消費數據的offset
 	    // consumer.seekToBeginning(list);
	 
 
	 /*    for(TopicPartition tpar:list ){
	    	 //consumer.seek(tpar, position);
	     } */
     
 
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + " pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
}

從指定時刻獲取數據

/**
 * @author yujie.wang
 * kafka消費者示例,包含隨機位置消費和最多一次消費方式
 * 消費者提交消費數據offset 分爲自動提交和手動控制提交
 * 
 * 這份代碼示例中包含了 多種從kafka的任意位置獲取數據的方式
 */
public class Consumer_Sample {
 
	//kafka集羣機器
	private static final String KAFKA_HOSTS = "10.4.30.151:9092,10.4.30.151:9093,10.4.30.151:9094";
	//topic名稱
	private static final String TOPIC = "my-replicated-topic_2";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Consumer_Sample consumer = new Consumer_Sample();
		
		// 通過實現ConsumerRebalanceListener接口 進而時間任意位置的消費
		consumer.consumerSubscribeImplListener("true", TOPIC);

		System.out.println("consumer end");
	}
	
	
	
	/**
	 * 
	 * @param isAutoCommitBool true 開啓自動提交offset;false 不開啓
	 * @param topic
	 * (1)如果該groupId消費者分組下 有消費者提交過offset,則從 當前提交的offset位置開始消費數據
	 * (2)如果該groupId消費者分組下 沒有有消費者提交過offset,則從 當前log添加的最後位置(也就是數據的末尾)開始消費數據
	 * 
	 * 注意如果enable.auto.commit 設置爲false,如果消費完數據沒有提交已消費數據的offset,
	 * 則會出現重複消費數據的情況
	 * 
	 * 通過實現ConsumerRebalanceListener接口中的onPartitionsAssigned方法,並在其中調用消費者的seek或者seekToBeginning
	 * 方法定位分區的任意位置或者開頭位置
	 */
	public void consumerSubscribeImplListener(final String isAutoCommitBool, final String topic){
		 Properties props = new Properties();
		 //配置kafka集羣機器
		 props.put("bootstrap.servers", KAFKA_HOSTS);
		 //消費者分組
		 props.put("group.id", "yujie26");
		 //這裏設置 消費者自動提交已消費消息的offset
		 props.put("enable.auto.commit", isAutoCommitBool);
		 // 設置自動提交的時間間隔爲1000毫秒
		 props.put("auto.commit.interval.ms", "1000");
		 // 設置每次poll的最大數據個數
		 props.put("max.poll.records", 5);
		 props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		 final KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
		 //訂閱topic,並實現ConsumerRebalanceListener
		 consumer.subscribe(Arrays.asList(topic), new ConsumerRebalanceListener(){
			@Override
			public void onPartitionsRevoked(//分區撤銷時,消費者可以向該分區提交自己當前的offset
					Collection<TopicPartition> collection) {
				// TODO Auto-generated method stub
				if("false".equalsIgnoreCase(isAutoCommitBool)){
					//consumer.commitSync();
				}
			}
 
			@Override
			public void onPartitionsAssigned(//當分區分配給消費者時,消費者可以通過該方法重新定位需要消費的數據位置
					Collection<TopicPartition> collection) {
				// TODO Auto-generated method stub
				//將消費者定位到各個分區的開始位置進行消費
		/*		consumer.seekToBeginning(collection);
				System.out.println("seek beg");*/
			
				Iterator it = collection.iterator();
				while(it.hasNext()){
					//將消費者定位到指定分區的指定位置7進行消費
					consumer.seek((TopicPartition)it.next(), 7);
				}
				
			}
		 });
		 while (true) {
		     ConsumerRecords<String, String> records = consumer.poll(5000);
		     System.out.println("topic: "+topic + "pool return records size: "+ records.count());
		     for (ConsumerRecord<String, String> record : records){
			 	 System.out.println(record.toString());
			 	  //手動提交已消費數據的offset
			 	 if("false".equalsIgnoreCase(isAutoCommitBool)){
			 		consumer.commitSync();
			 	 }
			 	
		     }
		   
		 }
	}
	
 
}

引用:https://blog.csdn.net/u011784767/article/details/78663168


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