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执行。