本文翻译自:http://storm.apache.org/releases/current/Tutorial.html
借鉴了:http://www.aboutyun.com/thread-7394-1-1.html
过去十几年数据处理取得了飞速的发展,特别是 MapReduce,Hadoop及其相关技术以不可思议的程度来进行大规模存储和处理,但是这些处理技术不够实时,Hadoop 系统也无法变成一个实时系统,因为实时数据处理系统需求是完全不同于批处理系统的。
但是业务需求却需要大规模实时数据处理,所以 Hadoop 就成为了数据处理生态系统中最大的一个短板。而Storm就弥补了这一不足。以前是人工建立网络队列和 worker 实时处理过程,所以存在严重的不足,比如数据队列冗长、系统易崩溃,也不适合大规模处理。现在 Storm极大地扩充了用例集、规模化、容错、数据不丢失等等特性,处理速度是非常快的。
一、Storm 基本构成部分
如图1所示。Nimbus 是通过 zookeeper 来传递信息的,也就是 zookeeper 在 nimbus 和 worker 之间建立了协调关系,所以对于 Strom 来说,zookeeper 至关重要。
早在 storm.yaml 配置中,我们定义supervisor.slots.ports: 有4个端口,这就是 worker 的工作端口,一个 supervisor 有4个 worker 端口。
节点有两个: master 节点、 worker 节点。master节点运行 Nimbus服务,worker 节点运行 Supervisor服务。
Nimbus 的作用:负责集群上的代码分配; 机器上的任务分配;监控失效数据
Supervisor 的作用:监听分配的工作;启动、停止worker进程。每一个 worker 进程就是运行一个 topology 的子集;一个 正在运行的topology分布在集群上每个机器上运行的如图2所示。正在运行的topology你可以通过 UI web端查看到。
图2
二、Topology 拓扑
Topology是 Storm中很重要的概念,这是处理实时计算的核心概念。一个 Topology就是一个计算的拓扑图,就是计算的路径和节点构成,而且这个图还是封闭的哟!不会自动计算完毕的,你得使用 Storm kill 来杀掉这个执行的Topology。Topology就包含了处理逻辑,节点间的连接,也就是节点间的数据是怎么传递的。
这个是运行的Topology:
$ storm jar storm-starter-1.1.0.jar org.apache.storm.starter.ExclamationTopology ExclamationTopology
三、Streams 数据流
Storm 中核心抽象概念就是 Stream, 数据流就是大量的一系列的tuples(元组)。Storm 用基元(primitives)以一种分布式的、可靠的方式将一个数据流转换成一个新的数据流。比如,将一个微博数据流变换一个热门话题数据流。
Storm 中提供的数据流转换基元就是 spout 和 bolt。spout 和 bolt 提供了对应的接口,实现这个接口就可以运行特定应用的逻辑。
一个 spout就是一个数据流的源,例如,可以从 Kestrel(storm-kestrel 开源)队列中弹出的元组作为一个 spout,并可以将它们作为一个数据流。还有一个 spout可以调用 Twitter API 得到一个微博数据流。下面的一个图就表明了从一个源头取tuple元组形成一个 spout !就是从外部数据源(队列、数据库等)中读取数据,封装成元组,形成数据流。
bolt 是用来处理数据里的,可以对一些数据流(不只一个数据流)进行处理,可能会产生新的数据流。对一些复杂的数据流变换,比如从一个微博流中计算一个热门话题流,就需要很多步骤,因此就有多个 bolt。因此 bolt 中就有很多处理,比如运行函数,做流式聚合,流式链接,访问数据库等等。bolts 就如下图所示。
从以上可以看出, spout 是一个 stream 的源, 而 bolt 却是处理输入的 streams,来产生新的 streams。注意,spout 和 bolt 只不过是流发生器而已。
spout 和 bolt组成的网络就是拓扑图Topology,如下图所示。Topology就是最高层的逻辑抽象,可以直接送到 Storm 集群去执行。一个Topology图就是流式转换,每个节点是 spout 或者 bolt。图中的每条边就是 bolt 订阅了流,当一个 spout或者 bolt 产生一个元组到一个流时,它就发送元组到订阅了流的每个 bolt。
四、数据模型
storm使用元组tuple来作为它的数据模型。每个tuple是一堆值,每个值有一个名字,并且每个值可以是任何类型, 在我的理解里面一个tuple可以看作一个没有方法的java对象。总体来看,storm支持所有的基本类型、字符串以及字节数组作为tuple的值类型。你也可以使用你自己定义的类型来作为值类型, 只要你实现对应的序列化器(serializer)。
topology里面的每个节点必须定义它要产生的tuple的每个字段。 比如下面这个bolt定义它所产生的tuple包含两个字段,类型分别是: double和triple。
public class DoubleAndTripleBolt extends BaseRichBolt {
private OutputCollectorBase _collector;
@Override
public void prepare(Map conf, TopologyContext context, OutputCollectorBase collector) {
_collector = collector;
}
@Override
public void execute(Tuple input) {
int val = input.getInteger(0);
_collector.emit(input, new Values(val*2, val*3));
_collector.ack(input);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("double", "triple"));
}
}
declareOutputFields方法定义要输出的字段 : ["double", "triple"]。这个bolt的其它部分我们接下来会解释。