disruptor异常分析

1. 背景

最近做领域驱动设计使用到disruptor组件,为了以后不会踩坑,阅读了disruptor部分源码,下面对disruptor生产者和消费者异常处理进行分析。

2. Disruptor生产者异常

Disruptor生产者异常和业务耦合的地方在Translator部分,这里从Disruptor类中的publishEvent方法入手:

// Disruptor类
public class Disruptor<T> {
  //......
  public void publishEvent(final EventTranslator<T> eventTranslator) {
    ringBuffer.publishEvent(eventTranslator);
  }
  //......
}

// RingBuffer类
public final class RingBuffer<E> extends RingBufferFields<E> implements Cursored, EventSequencer<E>, EventSink<E> {
  
  //......
  @Override
  public void publishEvent(EventTranslator<E> translator) {
    final long sequence = sequencer.next();
    translateAndPublish(translator, sequence);
  }
  
  private void translateAndPublish(EventTranslator<E> translator, long sequence) {
    try {
      // 这里translateTo方法由业务方来重写
      translator.translateTo(get(sequence), sequence);
    } finally {
      sequencer.publish(sequence);
    }
  }
  //......
}

RingBuffer类中的translateTo方法由业务方来重写,若在translateTo方法发生异常,发现上面的方法并未捕捉,在translateTo抛出异常之前会执行publish方法,会直接导致放到ring buffer中的event数据不完整(不是期待中的event数据),同时该进程不能再生产消息(即若该进程依次生成了两个event数据,若第一个event数据转换异常会导致第二个数据不会再生成),这里最好做一下异常捕捉。

3. 消费者异常

这里只说明消费者实现EventHandler接口的消费者类型,该消费者类型会有一个消费者线程不断地在轮询处理事件,实质上是BatchEventProcessor的run方法,

public final class BatchEventProcessor<T> implements EventProcessor {
  
  @Override
  public void run() {
    
    //......
    
    try {
      while (true) {
        try {  
          final long availableSequence = sequenceBarrier.waitFor(nextSequence);
          if (batchStartAware != null) {
            batchStartAware.onBatchStart(availableSequence - nextSequence + 1);
          }
          
          // 批处理在此处得以体现
          while (nextSequence <= availableSequence) {
            event = dataProvider.get(nextSequence);
            // 消费者处理具体业务
            eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
            nextSequence++;
          }
          // eventHandler处理完毕后,更新当前序号
          sequence.set(availableSequence);
        } catch (final TimeoutException e) {
          notifyTimeout(sequence.get());
        } catch (final AlertException ex) {
          if (!running.get()) {
            break;
          }
        } catch (final Throwable ex) {
          // 若业务代码中抛出异常,会被此处catch------------1
          exceptionHandler.handleEventException(ex, nextSequence, event);
          sequence.set(nextSequence);
          nextSequence++;
        }
      }
    } finally {
      //在处理器关闭之前立即通知EventHandler--------------------2
      notifyShutdown();
      running.set(false);
    }
  }
  //......
}



public final class FatalExceptionHandler implements ExceptionHandler<Object> {
    
  //......
  @Override
  public void handleEventException(final Throwable ex, final long sequence, final Object event) {
    logger.log(Level.SEVERE, "Exception processing: " + sequence + " " + event, ex);
    throw new RuntimeException(ex);
  }
  //......
}

若业务代码中抛出异常会被上述代码1处进行捕获,由于FatalExceptionHandler是exceptionHandler的默认实现,所会异常会由handleEventException方法来处理,即打印出log日志,同时抛出RuntimeException,最后会执行上面的2处,中止掉该消费者线程。会直接导致业务不被处理。

解决方案如下:

  • Step 1:实现ExceptionHandler接口

    public class DisruptorExceptionHandler<T> implements ExceptionHandler<T> {
        @Override
    	public void handleEventException(Throwable ex, long sequence, T event) {
            // 重写该方法
        }
    }
    
  • Step 2:设置默认异常处理器(disruptor默认的是FatalExceptionHandler)

    getDisruptor().setDefaultExceptionHandler(new DisruptorExceptionHandler<T>(getThreadName()));
    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bboyzqh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值