Apache storm Storm支持批处理

Apache storm Storm支持批处理,apache-storm,Apache Storm,我需要使用Storm处理成批的元组。我的最后一个螺栓必须等到拓扑接收到整个批次,然后才能进行一些处理。为避免混淆,batch for me是一组N条实时消息,该术语不必与批处理(Hadoop)联系起来。即使是两条消息也可以是一个批处理 阅读Storm的文档,可以安全地说Storm本身不支持这种批处理(实时批处理=N条消息) 我知道我们有三叉戟,但我没有使用它,但我做了一点测试。batchSpout的概念确实是我想要的,因为您可以使用收集器生成一个批,并且该批将作为单个批发出消息。但撇开三叉戟不谈

我需要使用Storm处理成批的元组。我的最后一个螺栓必须等到拓扑接收到整个批次,然后才能进行一些处理。为避免混淆,batch for me是一组N条实时消息,该术语不必与批处理(Hadoop)联系起来。即使是两条消息也可以是一个批处理

阅读Storm的文档,可以安全地说Storm本身不支持这种批处理(实时批处理=N条消息)

我知道我们有三叉戟,但我没有使用它,但我做了一点测试。batchSpout的概念确实是我想要的,因为您可以使用收集器生成一个批,并且该批将作为单个批发出消息。但撇开三叉戟不谈,普通风暴能提供什么

我是如何处理这个问题的,是通过使用元组确认和一些超时黑客(也许它们不是黑客?)。作为一个消息代理,我使用RabbitMQ,并制作了一个喷口,从队列中获取消息并将它们作为元组发送到下游,直到队列中不再有消息为止。这些元组经过几个阶段(3-4个阶段,又称螺栓),当它们到达最后一个螺栓时,它们就停在那里。我需要停止它们(不发出任何东西),因为正如我所说的,最后一个螺栓需要处理整个批次的结果,然后只发出一个元组(最终生成的元组)。那么,它如何知道什么时候应该进行处理呢?我让喷口负责发出信号。当喷口没有任何元组发出时,它将休眠10毫秒。因此,在休眠1000毫秒后,它将进入就绪状态(准备发出批处理结束或超时信号)。但还需要满足另一个条件。在我确定所有元组都到达最后一个螺栓之前,我无法发送信号。所以我使用了元组确认来跟踪这一点。当tuple到达最后一个螺栓时,它将被确认。当所有元组都得到确认,当喷口超时时,喷口发送信号,最后一个螺栓现在很高兴,它可以处理该批次元组的结果


所以我的问题是,我亲爱的风暴大师,这个拓扑是否设计得很糟糕,是否看起来像某种黑客?有没有更好的方法可以做到这一点?

Storm还提供。虽然他们不赞成使用三叉戟,但他们是在标准的风暴螺栓/喷口上实现的,所以没有理由不能继续使用它们。您也可以考虑将进程分成两个拓扑,在第二个拓扑中,直到有n个消息在RabBITMQ < /P> > P > >我的实现是替换Stur.Trutt.Primel.Purror .EcCurror,并创建一个扩展原始函数的新的BooBooType函数接口,因此,我可以公开每个处理器的startBatch&finishBatch方法,并且可以准确地知道一批元组何时开始以及何时结束

package storm.trident.operation;

import storm.trident.planner.ProcessorContext;

public interface BatchBoundaryFunction extends Function
{
    void startBatch(ProcessorContext processorContext, TridentCollector collector);

    void finishBatch(ProcessorContext processorContext, TridentCollector collector);
}



package storm.trident.planner.processor;

import java.util.List;
import java.util.Map;

import storm.trident.operation.BatchBoundaryFunction;
import storm.trident.operation.Function;
import storm.trident.operation.TridentOperationContext;
import storm.trident.planner.ProcessorContext;
import storm.trident.planner.TridentProcessor;
import storm.trident.tuple.TridentTuple;
import storm.trident.tuple.TridentTuple.Factory;
import storm.trident.tuple.TridentTupleView.ProjectionFactory;
import backtype.storm.task.TopologyContext;
import backtype.storm.tuple.Fields;

public class EachProcessor implements TridentProcessor
{
    Function _function;

    TridentContext _context;

    AppendCollector _collector;

    Fields _inputFields;

    ProjectionFactory _projection;

    public EachProcessor(Fields inputFields, Function function)
    {
        _function = function;
        _inputFields = inputFields;
    }

    @Override
    public void prepare(Map conf, TopologyContext context, TridentContext tridentContext)
    {
        List<Factory> parents = tridentContext.getParentTupleFactories();
        if (parents.size() != 1)
        {
            throw new RuntimeException("Each operation can only have one parent");
        }
        _context = tridentContext;
        _collector = new AppendCollector(tridentContext);
        _projection = new ProjectionFactory(parents.get(0), _inputFields);
        _function.prepare(conf, new TridentOperationContext(context, _projection));
    }

    @Override
    public void cleanup()
    {
        _function.cleanup();
    }

    @Override
    public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple)
    {
        _collector.setContext(processorContext, tuple);
        _function.execute(_projection.create(tuple), _collector);
    }

    @Override
    public void startBatch(ProcessorContext processorContext)
    {
        if (_function instanceof BatchBoundaryFunction)
        {
            ((BatchBoundaryFunction) _function).startBatch(processorContext, _collector);
        }
    }

    @Override
    public void finishBatch(ProcessorContext processorContext)
    {
        if (_function instanceof BatchBoundaryFunction)
        {
            ((BatchBoundaryFunction) _function).finishBatch(processorContext, _collector);
        }
    }

    @Override
    public Factory getOutputFactory()
    {
        return _collector.getOutputFactory();
    }
}
套装storm.trident.operation;
导入storm.trident.planner.ProcessorContext;
公共接口BatchBoundaryFunction扩展函数
{
void startBatch(ProcessorContext ProcessorContext,TridentCollector收集器);
void finishBatch(ProcessorContext ProcessorContext,TridentCollector收集器);
}
包storm.trident.planner.processor;
导入java.util.List;
导入java.util.Map;
导入storm.trident.operation.BatchBoundaryFunction;
导入storm.trident.operation.Function;
导入storm.trident.operation.TridentOperationContext;
导入storm.trident.planner.ProcessorContext;
导入storm.trident.planner.TridentProcessor;
导入storm.trident.tuple.tridentuple;
导入storm.trident.tuple.tridentuple.Factory;
导入storm.trident.tuple.TridentTupleView.ProjectionFactory;
导入backtype.storm.task.TopologyContext;
导入backtype.storm.tuple.Fields;
公共类EachProcessor实现TridentProcessor
{
函数_函数;
三位一体语境(TridentContext);;
附加收集器(u收集器),;
字段_输入字段;
投影工厂(ProjectionFactory)投影;;
公共每个处理器(字段、输入字段、函数)
{
_功能=功能;
_inputFields=inputFields;
}
@凌驾
公共空间准备(地图形态、地形上下文、TridentContext TridentContext)
{
List parents=tridentContext.getParentTupleFactorys();
if(parents.size()!=1)
{
抛出新的RuntimeException(“每个操作只能有一个父级”);
}
_上下文=三齿上下文;
_收集器=新的AppendCollector(tridentContext);
_projection=新的ProjectionFactory(parents.get(0),\u inputFields);
_准备(conf,newtridentOperationContext(context,_projection));
}
@凌驾
公共空间清理()
{
_function.cleanup();
}
@凌驾
public void execute(ProcessorContext ProcessorContext、String streamId、TridentTuple元组)
{
_setContext(processorContext,元组);
_execute(_projection.create(tuple),_collector);
}
@凌驾
公共无效开始批次(ProcessorContext ProcessorContext)
{
if(_BatchBoundaryFunction的函数实例)
{
((BatchBoundaryFunction)\u函数).startBatch(processorContext,\u收集器);
}
}
@凌驾
public void finishBatch(ProcessorContext ProcessorContext)
{
if(_BatchBoundaryFunction的函数实例)
{
((BatchBoundaryFunction)\u函数).finishBatch(processorContext,\u收集器);
}
}
@凌驾
公共工厂getOutputFactory()
{
返回_collector.getOutputFactory();
}
}

< /代码>我不会在回答中这样说,但是由于风暴的分布性质,您可能需要考虑在一些共享内存中聚合元组(<代码> ReISIS < /代码>),其中每个元组可能有一个值来指示它的状态。然后通过使用STORMS
勾选元组
可以