SpringBoot 1.5.4 版本和SpringBoot 2.7.18 在kafka重平衡对消费线程的处理方式略有差异

在1.5.4中SpringBoot对应的Spring kafka的版本

org.springframework.kafka:spring-kafka:1.1.6.RELEASE

在此版本的Spring对于kafka发生重平衡过程对消费线程的处理,会在awakeup之后打断消费线程,也就做优雅关闭的处理(设置消费线程的状态为interpred),具体的测试代码和现象如下

在消费session是15秒的基础下,我将业务的代码逻辑设置为100秒等待,显然这种情况会因为消费超时而发生重平衡,那么在较低版本的kafka的依赖支持上,那么会在执行awakeup之后执行消费线程的 interpret,具体的重平衡的效果会报错如下

这是因为在 org.springframework.kafka:spring-kafka:1.1.6.RELEASE中对kafka的重平衡,会先将所有的consumer的thread状态设置为interpred,具体的源码如下

所以在低版本的spring for kafka 中对于重平衡的处理,Spring 并不保证当前正在执行的消费线程能够正常执行完成,如果在过程中业务代码使用了Lock 、线程池可能会出现InterpretException的地方,那么业务执行就会被打断(比较致命),当然肯定很多人说一般应该避免非必要重平衡的发生,但是我现在的一个项目在重平衡过程中依然在消费订单,导致每一次的上下线,就会出现问题因为线程被中断

在2.7.18中SpringBoot对应的Spring kafka的版本是

org.springframework.kafka:spring-kafka:2.8.11

高版本的doStop的方法比较简单,kafka的支持 2.x的版本的代码更加的复杂

执行的流程是

  1. 检查isRunning() - 确保容器正在运行

  2. 注册StopCallback - 设置停止完成后的回调

  3. 设置running=false - 通知消费线程停止

  4. 调用wakeup() - 唤醒可能阻塞的消费线程

  5. 记录停止类型 - 标记为正常停止

  6. 消费线程检测到停止标志

  7. 完成当前消息处理

  8. 关闭consumer连接

  9. Future完成,触发StopCallback

  10. 执行回调,通知重平衡完成

对应的源码主要是

kotlin 复制代码
public void run() {
    ListenerUtils.setLogOnlyMetadata(this.containerProperties.isOnlyLogRecordMetadata());
    publishConsumerStartingEvent();
    this.consumerThread = Thread.currentThread();
    setupSeeks();
    KafkaUtils.setConsumerGroupId(this.consumerGroupId);
    this.count = 0;
    this.last = System.currentTimeMillis();
    initAssignedPartitions();
    publishConsumerStartedEvent();
    Throwable exitThrowable = null;
    while (isRunning()) {
       try {
          pollAndInvoke();
       }
       catch (NoOffsetForPartitionException nofpe) {
          this.fatalError = true;
          ListenerConsumer.this.logger.error(nofpe, "No offset and no reset policy");
          exitThrowable = nofpe;
          break;
       }
       catch (AuthenticationException | AuthorizationException ae) {
          if (this.authExceptionRetryInterval == null) {
             ListenerConsumer.this.logger.error(ae,
                   "Authentication/Authorization Exception and no authExceptionRetryInterval set");
             this.fatalError = true;
             exitThrowable = ae;
             break;
          }
          else {
             ListenerConsumer.this.logger.error(ae,
                   "Authentication/Authorization Exception, retrying in "
                         + this.authExceptionRetryInterval.toMillis() + " ms");
             // We can't pause/resume here, as KafkaConsumer doesn't take pausing
             // into account when committing, hence risk of being flooded with
             // GroupAuthorizationExceptions.
             // see: https://github.com/spring-projects/spring-kafka/pull/1337
             sleepFor(this.authExceptionRetryInterval);
          }
       }
       catch (FencedInstanceIdException fie) {
          this.fatalError = true;
          ListenerConsumer.this.logger.error(fie, "'" + ConsumerConfig.GROUP_INSTANCE_ID_CONFIG
                + "' has been fenced");
          exitThrowable = fie;
          break;
       }
       catch (StopAfterFenceException e) {
          this.logger.error(e, "Stopping container due to fencing");
          stop(false);
          exitThrowable = e;
       }
       catch (Error e) { // NOSONAR - rethrown
          this.logger.error(e, "Stopping container due to an Error");
          this.fatalError = true;
          wrapUp(e);
          throw e;
       }
       catch (Exception e) {
          handleConsumerException(e);
       }
       finally {
          clearThreadState();
       }
    }
    wrapUp(exitThrowable);
}

可见,在stop的时候 running直接退出,对于被invokeIfHaveRecords的数据会被等待执行完成 ,并不会影响正在执行的消费线程。

相关推荐
码事漫谈2 小时前
智能体颠覆教育行业调研报告:英语、编程、语文、数学学科应用分析
后端
蓝-萧2 小时前
使用Docker构建Node.js应用的详细指南
java·后端
码事漫谈3 小时前
《C语言点滴》——笑着入门,扎实成长
后端
Tony Bai3 小时前
【Go模块构建与依赖管理】09 企业级实践:私有仓库与私有 Proxy
开发语言·后端·golang
咖啡教室4 小时前
每日一个计算机小知识:ICMP
后端·网络协议
间彧4 小时前
OpenStack在混合云架构中通常扮演什么角色?
后端
咖啡教室4 小时前
每日一个计算机小知识:IGMP
后端·网络协议
间彧4 小时前
云原生技术栈中的核心组件(如Kubernetes、Docker)具体是如何协同工作的?
后端
清空mega4 小时前
从零开始搭建 flask 博客实验(3)
后端·python·flask
努力的小郑4 小时前
Elasticsearch 避坑指南:我在项目中总结的 14 条实用经验
后端·elasticsearch·性能优化