zoukankan      html  css  js  c++  java
  • spring kafka consumer原理解析二

    前言:

     在 spring kafka consumer原理解析一 里谈到了spring kafka 容器的加载过程,即每个 @KafkaListenner 会对应加载一个 CurrentMessageListennerContainer(一个多线程 kafka容器),而在 CurrentMessageListennerContainer 里面其实是创建了多个KafkaMessageListennerContainer (一个单线程 kafka 容器),到底创建几个是有 currency 这个参数指定。最终是在 kafkaMessageListennerContainer 创建 ListenerConsumer (一个线程类)调用 KafkaConsumer API 进行 kafka 的操作。然而通过调用 Kafka API 是如何进行操作的呢? see ↓

    解析:

    (1)ListenerConsumer (这个线程类是 Spring kafka 最终实现消费者代码的核心所在)

         private final class ListenerConsumer implements SchedulingAwareRunnable, ConsumerSeekCallback {
         @Override
    public void run() { if (this.theListener instanceof ConsumerSeekAware) { ((ConsumerSeekAware) this.theListener).registerSeekCallback(this); } this.count = 0; this.last = System.currentTimeMillis(); if (isRunning() && this.definedPartitions != null) {
              // 初始化分区:也就是通过 seekToEnd(kafka consumer API)获取最新的偏移量,然后将其保存起来 initPartitionsIfNeeded();
    // we start the invoker here as there will be no rebalance calls to // trigger it, but only if the container is not set to autocommit // otherwise we will process records on a separate thread
              // 判断是否是自动提交,如果不是自动提交则新开一个线程将数据(records)作为参数推至带有 @KafkaListener 方法中,然后手动提交为什么要新开一个线程呢?继续往下探索 ↓ if (!this.autoCommit) { startInvoker(); } } long lastReceive = System.currentTimeMillis(); long lastAlertAt = lastReceive; while (isRunning()) { try {
                // 如果是手动提交则判断现在是否要进行 commit
    if (!this.autoCommit) { processCommits(); }
                // 获取最新的偏移量 processSeeks();
    if (this.logger.isTraceEnabled()) { this.logger.trace("Polling (paused=" + this.paused + ")..."); }
                // 拉取数据 ConsumerRecords
    <K, V> records = this.consumer.poll(this.containerProperties.getPollTimeout()); if (records != null && this.logger.isDebugEnabled()) { this.logger.debug("Received: " + records.count() + " records"); } if (records != null && records.count() > 0) { if (this.containerProperties.getIdleEventInterval() != null) { lastReceive = System.currentTimeMillis(); } // if the container is set to auto-commit, then execute in the // same thread // otherwise send to the buffering queue
                   // 如果是自动提交则直接在这里将数据推送至带有 @KafkaListener 的方法中,相比手动提交不同的是:手动提交时新开了一个线程处理,而自动提交是在主线程执行这段逻辑。
                   // 为什么呢?这里说得很明白,因为设置为手动提交的时候,spring kafka 会把拉取下来的数据线放入一个队列中缓存起来,而推送线程是每次从那个缓存队列中获取数据推送过去,
                   // 而自动提交则是每次获取一点数据就直接推送过去 if (this.autoCommit) { invokeListener(records); } else {
                     // 这里是将数据存至缓存队列,如果缓存队列满了,则会调用 pause 暂停分区,即会停止拉取数据,直至缓存队列达到未满状态
    if (sendToListener(records)) { if (this.assignedPartitions != null) { // avoid group management rebalance due to a slow // consumer this.consumer.pause(this.assignedPartitions); this.paused = true; this.unsent = records; } } } } else { if (this.containerProperties.getIdleEventInterval() != null) { long now = System.currentTimeMillis(); if (now > lastReceive + this.containerProperties.getIdleEventInterval() && now > lastAlertAt + this.containerProperties.getIdleEventInterval()) { publishIdleContainerEvent(now - lastReceive); lastAlertAt = now; if (this.theListener instanceof ConsumerSeekAware) { seekPartitions(getAssignedPartitions(), true); } } } } this.unsent = checkPause(this.unsent); } catch (WakeupException e) { this.unsent = checkPause(this.unsent); } catch (Exception e) { if (this.containerProperties.getGenericErrorHandler() != null) { this.containerProperties.getGenericErrorHandler().handle(e, null); } else { this.logger.error("Container exception", e); } } } if (this.listenerInvokerFuture != null) { stopInvoker(); commitManualAcks(); } try { this.consumer.unsubscribe(); } catch (WakeupException e) { // No-op. Continue process } this.consumer.close(); if (this.logger.isInfoEnabled()) { this.logger.info("Consumer stopped"); } } }
  • 相关阅读:
    react-native中使用mobox数据共享
    vue cli3项目的pc自适应布局_vw
    webpack配置多页面和提取css
    react-native报错Encountered two children with the same key, `%s`.
    __proto__和prototype
    json-server配置模拟数据
    全局判断登录是否过期代码
    react-native环境搭建
    css的垂直居中常用几种方法
    进程和线程
  • 原文地址:https://www.cnblogs.com/lzj123/p/10749377.html
Copyright © 2011-2022 走看看