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的数据会被等待执行完成 ,并不会影响正在执行的消费线程。

相关推荐
想用offer打牌1 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX2 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法3 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte4 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行5 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple5 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
PP东5 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble6 小时前
springboot的核心实现机制原理
java·spring boot·后端