jstorm源码解析之bolt异常处理方法

作者:jingxian 时间:2022-08-05 23:12:08 

问题

用过storm或者jstorm的都知道,如果在bolt代码中发生了没被catch住的异常,所在worker进程会退出。本文就从源码角度分析一下具体设计,其实并不是“有异常然后进程崩了”这么简单。

实质

我们先看BasicBoltExecutor的源码:


 public void execute(Tuple input) {
   _collector.setContext(input);
   try {
     _bolt.execute(input, _collector);
     _collector.getOutputter().ack(input);
   } catch (FailedException e) {
     if (e instanceof ReportedFailedException) {
       _collector.reportError(e);
     }
     _collector.getOutputter().fail(input);
   }
 }

_bolt.execute(input, _collector) 就是执行我们自己编写的bolt里的excute方法。可以看到,在这里,只会catch storm自己定义的FailedException,并且发送fail消息,标记tuple处理失败, 其余异常则会被放过。

再外层是BoltExecutors的processTupleEvent方法:


   try {
     if (!isSystemBolt && tuple.getSourceStreamId().equals(Common.TOPOLOGY_MASTER_CONTROL_STREAM_ID)) {
       backpressureTrigger.handle(tuple);
     } else {
       bolt.execute(tuple);
     }
   } catch (Throwable e) {
     error = e;
     LOG.error("bolt execute error ", e);
     report_error.report(e);
   }

在这里,所有异常都会被catch住,但是只会进行report_error,并不会发fail消息,相关tuple只能等超时才能被标记为失败。

再来看report_error.report(e) 的具体实现,通过看构造函数,可以看到report_error是一个TaskReportErrorAndDie类,


 @Override
 public void report(Throwable error) {
   this.reporterror.report(error);
   this.haltfn.run();
 }

在这里,reporterror是一个AsyncLoopDefaultKill类


 @Override
 public void run() {
   JStormUtils.halt_process(1, "Async loop died!");
 }

这里就是整个过程的最终步骤了, JStormUtils.halt_process()方法会打印一条"Async loop died!"的日志后将worker进程杀死。

思考

通过代码可以出来,对于jstorm,“异常后worker退出”是一个故意设计出的特性,并非程序不健壮。猜测这一块的设计理念就是对于已知异常,开发人员自己捕获并重新抛出FailedException,使相应消息失败;未知异常则强制使进程直接失败退出,避免过度的catch导致问题被掩盖。

不过虽然话是这么说,对这个设计还是持保留意见,毕竟storm和普通的java程序不一样,storm的worker进程在退出后是会自动被重启的,所以这种异常处理方式并不能起到failfast的效果。

相反,worker的持续重启,还会带来一些其他问题。再一个,不主动将消息标为失败,而是等超时,如果设置的超时时间过长(当然超时时间太长也不合理),也会引入一些问题。比如说kafkaSpout, 一条消息没被ack之前是不会继续取后边的数据的,这样如果有一条数据需要等超时,同分区下的数据在这一个超时周期内,就都无法被处理了。

从另一方面来说,如果像FailedException一样处理其他所有异常,由于异常之后可以看到有数据fail,也并不会掩盖问题。

所以说,这一块的处理逻辑,个人感觉还是需要斟酌一下。

标签:jstorm,bolt,异常处理
0
投稿

猜你喜欢

  • 你所不知道的Spring的@Autowired实现细节分析

    2023-11-25 05:40:47
  • Java 静态代理与动态 代理解析

    2023-08-22 17:18:19
  • java实现的简单猜数字游戏代码

    2023-06-17 22:56:22
  • java注解的全面分析

    2023-11-25 11:28:50
  • gson对象序列化的示例

    2023-11-25 08:54:28
  • c#取得控制台应用程序根目录

    2023-06-16 14:25:44
  • 自定义类加载器以及打破双亲委派模型解析

    2023-06-22 22:03:59
  • Android 显示GIF图片实例详解

    2023-08-06 09:11:52
  • springboot cloud使用eureka整合分布式事务组件Seata 的方法

    2023-08-19 13:49:44
  • Java内存模型之happens-before概念详解

    2023-11-23 03:11:50
  • java中JVM中如何存取数据和相关信息详解

    2023-08-10 03:49:46
  • 详解spring中的Aware接口功能

    2023-07-02 00:36:01
  • SpringBoot配置全局异常处理器捕获异常详解

    2023-11-28 05:08:07
  • eclipse实现ElGamal数字签名

    2023-11-26 07:52:47
  • slf4j jcl jul log4j1 log4j2 logback各组件系统日志切换

    2023-08-08 13:00:41
  • Java8时间api之LocalDate/LocalDateTime的用法详解

    2023-11-10 16:14:43
  • Java中的泛型方法详解及简单实例

    2023-09-11 13:28:05
  • java字符串相似度算法

    2023-11-26 12:33:25
  • Java使用application.property读取文件里面的值

    2023-11-01 07:24:56
  • SpringBoot项目从搭建到发布一条龙

    2023-11-21 09:28:44
  • asp之家 软件编程 m.aspxhome.com