kafka消費者偏移量手動管理-同步提交
首先,我們將參數enable.auto.commit參數的值設爲false。不進行自動偏移量提交。進行如下代碼。手動提交偏移量。爲了模擬再均衡或者消費者異常終止的情況出現的偏移量未提交的現象,我們在提交偏移量之前,讓線程休眠10s。代碼如下
package com.xx.cn.kafka;
import cn.hutool.setting.dialect.Props;
import com.xx.cn.common.KafkaParams;
import org.apache.kafka.clients.consumer.CommitFailedException;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Properties;
/**
* 〈一句話功能簡述〉<br>
* 〈提交偏移量〉
*共四個步驟
* 1. 準備連接參數
* 2. 訂閱主題
* 3. 拉取數據
* 4. 同步提交偏移量
*/
public class ConsumerCommitOffset {
public static final Logger logger = LoggerFactory.getLogger(ConsumerCommitOffset.class);
public static void main(String[] args) {
//校驗參數
if(args.length<2){
System.out.println("args must be [config] runMode[prd|prev]");
System.exit(-1);
}
String config = args[0];
String runMode = args[1];
Properties props = kafakParams(config, runMode);
//創建消費者客戶端
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
//訂閱主題
consumer.subscribe(Collections.singletonList("country"));
while (true){
ConsumerRecords<String, String> records = consumer.poll(100);
for (ConsumerRecord<String, String> record : records) {
processRecord(record);
}
try {
Thread.sleep(10000);
//在每個批次後,同步提交偏移量。等待提交成功後,進行下一批次數據拉取
consumer.commitSync();
logger.info("offset commit finish" );
} catch (InterruptedException e) {
logger.error(e.getMessage());
} catch (CommitFailedException e ){
logger.error(e.getMessage());
}
}
}
private static void processRecord(ConsumerRecord<String, String> record) {
System.out.printf(
"topic = %s , partition = %s ,offset= %s ,key =%s ,value =%s\n",
record.topic(),record.partition(),record.offset(),record.key(),record.value()
);
}
private static Properties kafakParams(String config,String runMode){
Props properties = new Props(config);
Properties props = new Properties();
props.put(KafkaParams.BOOTSTRAP_SERVERS, properties.getStr(KafkaParams.BOOTSTRAP_SERVERS));
props.put(KafkaParams.GROUP_ID, "pen");
props.put(KafkaParams.KEY_DESERIALIZER, StringDeserializer.class);
props.put(KafkaParams.VALUE_DESERIALIZER, StringDeserializer.class);
props.put(KafkaParams.AUTO_OFFSET_RESET, properties.getStr(KafkaParams.AUTO_OFFSET_RESET));
props.put(KafkaParams.ENABLE_AUTO_COMMIT,properties.getBool(KafkaParams.ENABLE_AUTO_COMMIT));
if (runMode.equals("prev")){
props.put(KafkaParams.SECURITY_PROTOCOL, properties.getStr(KafkaParams.SECURITY_PROTOCOL));
props.put(KafkaParams.SASL_MECHANISM, properties.getStr(KafkaParams.SASL_MECHANISM));
props.put(KafkaParams.SASL_JAAS_CONFIG, properties.getStr(KafkaParams.SASL_JAAS_CONFIG));
}
return props;
}
}
使用客戶端模擬生產者,寫入數據 (jingzhuang + num的方式)。
情況1:在完成偏移量提交後,終止消費者。按照理論,完成了最後消費,並提交偏移量之後,重啓消費者消息不會出現重複。
終止程序前的日誌
page1
重啓程序的日誌,可以看到重啓消費者後,沒有重複消費
page2
這次我們在沒有進行最後一次 jingzhuang 6 這次消息的偏移量的提交時候,終止程序。理論上來說,再次啓動會重複消費 jingzhuang6這條數據,因爲本消息的偏移量沒有被提交。
page3
實際情況與我們預期相符和。
因此,用不提交偏移量,如果程序在最後一個批次沒有處理完成的情況下終止,下次重啓會出現重複消費的情況。另外我們使用consumer.commitSync() 同步提交偏移量,會在沒有提交成功的時候一直等待,降低消費吞吐。但是優點是,在沒有提交成功,會按照配置進行重試,可以降低消費重複的數量。