storm源码分析研究(十)

2021SC@SDUSC

Trident的Spout节点分析

2021SC@SDUSC

Trident是Storm提供给用户的另外一套接口,它提供了基本的流处理功能以及可靠的消息处理功能,其中对流的操作是Trident的核心。

Trident主要支持两种类型的Spout节点:ITridentSpout以及DRPC Spout。对于Storm中其他基本类型的Spout , 例如IRichSpout和IBatchSpout,Trident进行了接口适配,将它们适配成为ITridentSpout接口并在Topology中执行。

本篇将略微分析这些Spout节点及适配Spout节点的执行器。

TridentSpoutCoordinator.java

TridentSpoutCoordinator类为BatchCoordinator的执行器 ,它继承自IBasicBolt接口,实际上为Bolt节点,主要用于执行协调Spout接口中的initializeTransaction方法。

public class TridentSpoutCoordinator implements IBasicBolt {
    public static final Logger LOG = LoggerFactory.getLogger(TridentSpoutCoordinator.class);
    private static final String META_DIR = "meta";

    ITridentSpout<Object> spout;
    ITridentSpout.BatchCoordinator<Object> coord;
    RotatingTransactionalState state;
    TransactionalState underlyingState;
    String id;


    public TridentSpoutCoordinator(String id, ITridentSpout<Object> spout) {
        this.spout = spout;
        this.id = id;
    }

    @Override
    public void prepare(Map<String, Object> conf, TopologyContext context) {
        coord = spout.getCoordinator(id, conf, context);
        underlyingState = TransactionalState.newCoordinatorState(conf, id);
        state = new RotatingTransactionalState(underlyingState, META_DIR);
    }

    @Override
    public void execute(Tuple tuple, BasicOutputCollector collector) {
        TransactionAttempt attempt = (TransactionAttempt) tuple.getValue(0);

        if (tuple.getSourceStreamId().equals(MasterBatchCoordinator.SUCCESS_STREAM_ID)) {
            state.cleanupBefore(attempt.getTransactionId());
            coord.success(attempt.getTransactionId());
        } else {
            long txid = attempt.getTransactionId();
            Object prevMeta = state.getPreviousState(txid);
            Object meta = coord.initializeTransaction(txid, prevMeta, state.getState(txid));
            state.overrideState(txid, meta);
            collector.emit(MasterBatchCoordinator.BATCH_STREAM_ID, new Values(attempt, meta));
        }

    }

    @Override
    public void cleanup() {
        coord.close();
        underlyingState.close();
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declareStream(MasterBatchCoordinator.BATCH_STREAM_ID, new Fields("tx", "metadata"));
    }

    @Override
    public Map<String, Object> getComponentConfiguration() {
        Config ret = new Config();
        ret.setMaxTaskParallelism(1);
        return ret;
    }
}

在execute方法的实现中,TridentSpoutCoordinator将接收success和batch 流,这两个流只包含一列,即事务序号txid。

当收到success流的消息时,表明事务处理已经结束,于是调用_coord的success方法,同时清理ZooKeeper中的元数据。

当收到batch消息时,execute方法会初始化一个事务并将消息发送到$batch流中,消息的格式为<tx,metadata>,由于收到的消息可能是重传的消息,例如由Spout的超时引发的重传,此时事务所对应的元数据可能已经存在,这也是initializeTransaction方法有prevMeta参数的原因。

Trident是在Bolt节点中对事务进行初始化的,这与事务Topology也不同,后者在Spout节点中产生。

MasterBatchCoordinator.java

MasterBatchCoordinator类是Trident中真正的Spout节点。Trident中可以含有多个MasterBatchCoordinator类型的Spout节点,每个Spout节点又进一步对应于一个含有存储节点的节点组
每个MasterBatchCoordinator节点可以对应多个ITridentSpout节点,这些ITridentSpout节点属于同一个节点组。
MasterBatchCoordinator类用来产生一个新的事务以及判断一个事务是否已经被成功处理。

Trident 中分区的 Spout 类型

分区 Spout 接口
IPartitionedTridentSpout.java

public interface IPartitionedTridentSpout<PartitionsT, PartitionT extends ISpoutPartition, T> extends ITridentDataSource {
    Coordinator<PartitionsT> getCoordinator(Map<String, Object> conf, TopologyContext context);

    Emitter<PartitionsT, PartitionT, T> getEmitter(Map<String, Object> conf, TopologyContext context);

    Map<String, Object> getComponentConfiguration();

    Fields getOutputFields();

    interface Coordinator<PartitionsT> {

        PartitionsT getPartitionsForBatch();

        boolean isReady(long txid);

        void close();
    }

    interface Emitter<PartitionsT, PartitionT extends ISpoutPartition, X> {

        List<PartitionT> getOrderedPartitions(PartitionsT allPartitionInfo);
        
        X emitPartitionBatchNew(TransactionAttempt tx, TridentCollector collector, PartitionT partition, X lastPartitionMeta);

        void refreshPartitions(List<PartitionT> partitionResponsibilities);

        void emitPartitionBatch(TransactionAttempt tx, TridentCollector collector, PartitionT partition, X partitionMeta);

        default List<PartitionT> getPartitionsForTask(int taskId, int numTasks, List<PartitionT> allPartitionInfoSorted) {
            List<PartitionT> taskPartitions = new ArrayList<>(allPartitionInfoSorted == null ? 0 : allPartitionInfoSorted.size());
            if (allPartitionInfoSorted != null) {
                for (int i = taskId; i < allPartitionInfoSorted.size(); i += numTasks) {
                    taskPartitions.add(allPartitionInfoSorted.get(i));
                }
            }
            return taskPartitions;
        }

        void close();
    }
}

}
IPartitionedTridentSpout中有3个通用类型:Partitions、Partition和X。Coordinator中存储数据的类型为Partitions, 为通用类型,其含义为分区的元数据。

在 IPartitionedTrident 接 口 中 ,通 过 调 用 getOrderedPartitions 方 法 根 据输入的Partitions类型获得Partition的列表。同样地,Partition也为通用类型,但是它要继承自ISpoutPartition接口,即含有getld方法来获得Partition的编号ID。

类型X表示处理某个Partition在某一个事务上面对应的元数据类型。

Coordinator的isReady方法用来判断输人的事务是否可以开始。

分区 Spout 的执行器
PartitionedTridentSpoutExecutor.java
该类实现了 ITridentSpout 接 口 ,它 对 IPartitionedTridentSpout进行了适配,使其能够被Trident执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值