Storm 入门笔记1
storm 是一个老牌的实时流处理框架。Hadoop的Mapreduce, spark的RDD ,都受到函数式编程的启发,通过纯函数式的接口,不断地对数据进行变换,过滤,聚合,从而得到最终结果。
函数式的编程模型容易理解,容易编写,也容易测试。而storm的模型相比之下要更复杂和开放。
入门storm的第一步,就是厘清这些纠缠的,隐晦的编程模型。
这篇笔记参考了了storm官网的Concepts一章,加上自己的理解。
Topology
topology是storm的一个顶层概念,由许多Spout (消息生产者)和Bolt(消息生产者和消费者) 组成。就像Hadoop的Mapreduce Job , 或者Spark中的RDD DAG ,topology 也是一个有向无环图。 但与前两个模型不同,topology 处理的是实时数据,理论上数据流的长度是无限的,所以topology 不会因为计算完成而结束。
Mapreduce 计算的时候分为map 阶段和reduce 阶段,两者之间有先后关系。Spark的DAG 也被分成stage,stage按照先后顺序排队执行。对于Storm 来说,spout和 topology 没有明确的先后顺序,流数据的生产和消费过程一直存在。
Spout
spout 是流数据的生产者。也就是数据源。只生产不消费。所有的topology 都是从一个或者多个spout开始的。 Spout 接口和类如上图所示。如果直接实现IRichSpout接口,就需要重写接口的所有方法,所以最常见的情况就是继承BaseRichSpout,然后重写open 和 nextTuple方法。
open
方法有三个参数,入门阶段只需要关心第三个参数,一个类型是SpoutOutputCollector的变量collector。通常Spout子类会定义一个SpoutOutputCollector 类的私有变量,然后在open
方法中把collector赋值给 同类型的私有变量。
nextTuple
就是Spout 发送数据的地方。Storm通过调用spout类的nextTuple方法来生产数据。这个方法必须是非阻塞的(non-blocking), 如果此时没有数据要发送,可以直接return 。
Bolt
bolt 是流数据的处理单元,它是数据的消费者,也可以是数据的生产者。你可以对数据进行变换,过滤,聚合,写入持久化的存储,等等等等。多个bolt 可以组成一个流处理流水线,也可能组成一个有向无环图,就像RDD的DAG那样。
Bolt 类型的核心是execute
方法,这是Bolt类接收并处理消息的地方。Bolt 通过一个OutputCollector 对象发送处理过的消息。这个对象可能来自prepare
方法,或者execute
方法。
Stream & Tuple
stream 顾名思义就是流处理的对象——数据流。数据流是一个无穷的序列,而序列中的每一个元素,就是tuple。storm的数据处理,也是以tuple为核心的。Bolt 类的execute
的第一个参数就是Tuple对象。
void execute(Tuple input);
如果你熟悉Python或者Scala,对于tuple就不会陌生。Storm中的tuple 实际上只是一个封装过的数据列表,类似Python中的named tuple 或者Scala 中的case class,可以通过index 访问字段,也可以通过字段名访问。 当你发送一个新的tuple时,通常会调用OutputCollector
对象的emit 方法
public List<Integer> emit(List<Object> tuple) {
return emit(Utils.DEFAULT_STREAM_ID, tuple);
}
List<Object>
封装了一条消息。而每个字段的名字,通过调用declareOutputFields
的方法来声明。 给字段起名字有什么用?这就跟Storm的Grouping机制有关系了。