kafka定時任務拉取數據

1  定時任務兩種, 2 消費分組消費從哪裏開始,不消費歷史數據  

  定時主要是爲了延遲拉消費,最簡單方式  直接批量拉取之後, ack批量提交後, 線程掛起3秒,更好達到效果

  if (kafuKfaUtils.insertFlowdata(jsonarray, map)) {
                    ack.acknowledge();
                }
提交之後, 再等待幾秒,以拉取更多數據    
    
    long start = System.currentTimeMillis();
            System.out.println("線程掛起2秒" + start);
            Thread.sleep(2000);//睡眠5秒
            long end = System.currentTimeMillis();
            System.out.println("線程恢復" + (end - start) / 1000);

第一種監聽的方式定時

springboot1.5.6 + kafka2.1.7 依賴包  包衝突後,  又改回springboot-kafka1.1.1  定時任務不理想,恢復和暫停有問題

      <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.1.7.RELEASE</version>
        </dependency>

注入實例  當執行完成後, 取消監聽topic  定時開啓監控,這個在KAFKA之前的版本並不支持 監聽和取消 ,我升級包後纔行

後面主要是邏輯代碼了, 後面貼上  

@KafkaListener(id = "flow-task", topics = "topic_collect", group = "flow-topic", containerFactory = "batchFlowFactory")  低版本沒有groupId 兼容問題,暫停會有問題,
@Service
public class KafkaTaskService {
    private static final Logger log = LoggerFactory.getLogger(KafkaTaskService.class);
    @Autowired
    private              KafkaListenerEndpointRegistry registry;

    /**
     * 定時執行
     *
     * @param recordList
     * @param acknowledgment
     */
    @KafkaListener(id = "flow-task", topics = "topic_collect", group = "flow-topic", containerFactory = "batchFlowFactory")
    public void listenFailEmail(List<ConsumerRecord> recordList, Acknowledgment acknowledgment) {
        System.out.println(recordList.size() + "條數據,監聽消費開始");
        for (ConsumerRecord record : recordList) {
            log.info("fail email-消息:【{}】。", record.value().toString());
        }
        acknowledgment.acknowledge();
        shutdownListener();
        System.out.println("********* 監聽消費結束");
    }

    @Scheduled(cron = "0/20 * * * * ?")
    public void startListener() {
        log.info("開啓監聽");
        MessageListenerContainer container = registry.getListenerContainer("flow-task");
        if (!container.isRunning()) {
            container.start();
            System.out.println("開啓監聽");
        }
        //恢復
        //  container.resume();
    }

    //@Scheduled(cron = "0 08 12 * * ?")  //12點08分執行
    public void shutdownListener() {
        //  log.info("關閉監聽");
        //暫停
        MessageListenerContainer container = registry.getListenerContainer("flow-task");
        container.stop();
        System.out.println("關閉監聽");
        //  conta

    /**
     * kafka監聽工廠
     *
     * @param configurer
     * @return
     */
    @Bean("batchFactory")
    public ConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(
            ConcurrentKafkaListenerContainerFactoryConfigurer configurer,
            ConsumerFactory consumerFactory) {
        ConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory);
        //開啓批量消費功能
        factory.setBatchListener(true);
        //不自動啓動
        factory.setAutoStartup(false);
        configurer.configure(factory, consumerFactory);
        return factory;
    }
}

 

定時任務第二種方式

通過實踐獲取一下結論:

1.topic可以被多個group消費
group之間消費位移互不干擾
2.topic被group消費時,若有多個消費者實例,同一條消息只會被一個消費者處理
3.一個group可以消費多個topic
4.一個消費者group可以拉取多個topic消息

代碼如下 核心代碼  加入新分組可以定時拉任務, 但結果不是自己想要的,一分鐘拉一次,數據處理不完的時候,會怎麼樣

@EnableAsync
@Component
public class GroupQueue {
    static boolean RUN = false;

    @Async
    @Scheduled(cron = "0 * * * * ?")
    public void task() {
        if (RUN) {
            return;
        }
        RUN = true;
        KafkaConsumer consumer = KafkaConsumerFactory.getKafkaConsumer("group2");
        consumer.subscribe(Arrays.asList("GroupQueue", "FriendQueue"));

        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            System.out.println("批次:" + UUID.randomUUID().toString());

            for (ConsumerRecord<String, String> record : records) {
                System.out.printf(record.topic() +
                    "一條新消息 offset = %d, key = %s, value = %s", record.offset(),
                    record.key(), record.value());
                System.out.println(record.topic() + "partition:" +
                    record.partition());

                // 業務處理 TODO
            }

            // 同步提交
            if (records.count() > 0) {
                consumer.commitSync();
                System.out.println("批次提交");
            }
        }
    }

    public static KafkaConsumer getKafkaConsumer(String group) {
        Properties propstask = new Properties();
        propstask.put("bootstrap.servers", "107.101.117.118:9092 107.101.117.119:9092 107.101.117.117:9092");
        //每個消費者分配獨立的組號
        propstask.put("group.id", group);
        //如果value合法,則自動提交偏移量
        propstask.put("enable.auto.commit", "false");
        // 每次拉取5000條
        propstask.put("max.poll.records", 10000);
        //設置多久一次更新被消費消息的偏移量
        propstask.put("auto.commit.interval.ms", "1000");
        //設置會話響應的時間,超過這個時間kafka可以選擇放棄消費或者消費下一條消息
        propstask.put("session.timeout.ms", "30000");
        //自動重置offset
        propstask.put("auto.offset.reset", "latest");//latest  earliest
        propstask.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        propstask.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        return new KafkaConsumer<String, String>(propstask);
    }

}

不消費歷史數據,添加分組消費最新數據,放棄消費歷史數據等

設置消費者properties的兩個參數

consumer.group.id

properties.setProperty("auto.offset.reset", "earliest”) // latest

注意:

只要不更改group.id,每次重新消費kafka,都是從上次消費結束的地方繼續開始,不論"auto.offset.reset”屬性設置的是什麼

 

場景一:Kafka上在實時被灌入數據,但kafka上已經積累了兩天的數據,如何從最新的offset開始消費?

(最新指相對於當前系統時間最新)

1.將group.id換成新的名字(相當於加入新的消費組)

 

2.網上文章寫還要設置 properties.setProperty("auto.offset.reset", "latest”)

實驗發現即使不設置這個,只要group.id是全新的,就會從最新的的offset開始消費

 

場景二:kafka在實時在灌入數據,kafka上已經積累了兩天的數據,如何從兩天前最開始的位置消費?

1.將group.id換成新的名字

2.properties.setProperty("auto.offset.reset", "earliest”)

 

場景三:不更改group.id,只是添加了properties.setProperty("auto.offset.reset", "earliest”),consumer會從兩天前最開始的位置消費嗎?

不會,只要不更改消費組,只會從上次消費結束的地方繼續消費

 

場景四:不更改group.id,只是添加了properties.setProperty("auto.offset.reset", "latest”),consumer會從距離現在最近的位置消費嗎?

不會,只要不更改消費組,只會從上次消費結束的地方繼續消費

 

應用:

正式打包上線前應該使用新的group.id,以便於從kafka最新的位置開始消費

只要將group.id換成全新的,不論"auto.offset.reset”是否設置,設置成什麼,都會從最新的位置開始消費

 

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