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

相关推荐
程序猿DD14 分钟前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i3 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8263 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
凤山老林4 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne5 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF5 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li6 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
upala6 小时前
【仓颉语言入门 · 第二篇 第 6 课】
后端
罗丹丹Luna6 小时前
移动端显示“已提交”以后:SAP 与低代码集成该怎样暴露真实状态
后端·架构
码事漫谈6 小时前
因为太想讨好你,所以AI会骗你
后端