storm的学习与使用(一)

来源:互联网 发布:qq三国js技能介绍 编辑:程序博客网 时间:2024/04/30 22:36

一个Storm集群的基本组件

storm的集群表面上看和hadoop的集群非常像。但是在hadoop上运行的MapReduce的Job的,在storm上运行的是Topology。一个关键的区别在于,一个MapReduce Job最终会结束,但是一个Topology会永远运行下去,除非你显式的杀掉它。

在storm的集群上有两种节点:控制节点和工作节点。控制节点上面运行一个后台程序Nimbus,它的作用类似于Hadoop里面的JobTracker.Nimbus负责在集群里面分布代码,分配给机器工作,并且监控状态。

每一个工作节点上面运行一个叫做supervisor的节点。supervisor会监听分配给它这台机器的工作,根据需要启动/关闭工作进程。每一个工作进程执行一个Topology的一个子集,一个运行的Topology由运行在很多机器上的很多工作进程组成。

Nimbus和Supervisor之间的所有协调工作都是通过一个Zookeeper集群来完成的。并且Nimbus和Supervisor都是快速失效(fast-fail)的,无状态的,所有的状态要么在zookeeper上面,要么在本地磁盘上。这也就意味着你可以随时kill -9杀掉nimbus或者supervisor,然后再重启他们,他们可以继续工作,就像什么都没发生一样,这个设计使得storm不可思议的稳定。


Topologies

为了在storm上面做实时计算,你要去建立一些topologies.一个topology就是一个计算节点所组成的图。topology里面的每个处理节点都包含处理逻辑,而节点之间的连接则表示数据流动的方向。

运行一个storm是很简单的。首先,将你的所有代码以及所依赖的jar打包进一个jar。然后运行类似如下命令:

strom jar all-your-code.jar backtype.storm.MyTopology arg1 arg2
这个命令运行MyTopology这个类,参数为arg1,arg2.这个类定义一个topo,并将它发布到Nimbus上。storm的jar负责连接到nimbus上并且上传jar文件。


因为topology的定义其实就是一个Thrift结构,并且nimbus就是一个Thrift服务,又可以用任何语言创建并提交topology.(注意学习Thrift和storm的脚本)


Stream(什么叫原语)

stream是storm里面的关键抽象。一个stream是一个没有边界的tuple序列。storm提供一些原语来分布式的,可靠的把一个stream传输进一个新的stream。

storm提供的最基本的处理stream的原语是spout和bolt。你可以实现spout和bolt对应的接口已处理你的逻辑。

spout是流的源头。比如一个spout可能从K队列里面读取消息并且把这个消息发射成一个流。又比如一个spout可以调用一个spi把返回的消息作为一个流

bolt可以接受任意多个输入的stream,做一些处理,有些bolt还会发射一些新的stream.bolt是主要的处理逻辑,里面可以做任何事情:运行函数,过滤tuple,做一些聚合,做一些合并以及访问数据库等等。

spout和bolt所组成的网络会被打包成topology,topo是storm里面最高一级的抽象,你可以把topo交给storm的集群来运行。


topo里面的每一个节点都是并行运行的。在你的topo里面,你可以指定每个节点的并行度,storm则会在集群里面分配那么多线程来同时计算。

一个topology会一直运行直到你显式停止它。storm自动重新分配一些失败的任务,并且保证你不会有数据的丢失,及时一些机器意外停机并且消息被丢掉。


数据模型(注意自定义的类型要序列化,发射tuple时字段数目要对应上)

storm使用tuple来作为它的数据模型。每个tuple都是一堆值,每个值都有一个名字,并且每个值都可以是任何类型。可以理解tuple为一个没有方法的java对象。storm支持所有的基本类型,字符串以及字节数组作为tuple的值类型,也可以使用自定义类型作为类型,只要实现对应的序列化器。

topo里面的每个节点必须定义它要发射的tuple的每个字段。也就是说,如果一个tuple里面包含3个字段,就要写3个,有4个写4个

public class DoubleAndTripleBolt implements IRichBolt {    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 cleanup() {    }     @Override    public void declareOutputFields(OutputFieldsDeclarer declarer) {        declarer.declare(new Fields("double", "triple"));    }}

一个简单的topology

TopologyBuilder builder = new TopologyBuilder();builder.setSpout(1, new TestWordSpout(), 10);builder.setBolt(2, new ExclamationBolt(), 3).shuffleGrouping(1);builder.setBolt(3, new ExclamationBolt(), 2).shuffleGrouping(2);
setSpout与setBolt方法,三个参数分别是,我们指定的id,也就是这个组件的唯一id,一个包含处理逻辑的对象,以及一个并行度

这个处理逻辑的对象要实现spout或者bolt接口

并行度是可选的,默认是1

prepare方法提供给bolt一个Outputcollector用来发射tuple.Bolt可以再任何时候发射tuple,在prepare,execute或者cleanup方法里面,或者设置在另一个线程里面异步发射(注意:这个异步可能会出现问题,emit最好由同一个线程去执行,否则会出现未序列化的异常)

execute方法从bolt的一个输入接受tuple,bolt可以有多个输入源,可以通过getSourceComponent方法知道它是来自哪个输入源。

可以直接使用collector.emit(new Values("word")),或者collector.emit(tuple, new Values("word"))

cleanup方法在bolt被关闭的时候调用,它应该清理多有被打开的资源。但是集群不保证这个方法一定会被执行。cleanup设计的时候是被用来在local mode的时候才被调用(也就是一个进程里面模拟曾哥storm集群时),并且在你想关闭一些topo的时候避免资源泄露


提交topo时需要三个参数,一个是topo的名字,一个是conf对象,还有一个是创建的topo

conf对象可以配置很多东西,最常见的有2个

1.TOPOLOGY_WORKERS,工作进程的数量

2.TOPOLOGY_DEBUG,当设置为true时,storm会记录下每个组件所发射的每条消息,这个会影响性能,小心使用。


流分组策略

流分组策略告诉topo如何在两个组件之间发送tuple。当bolt A的一个task要发送给另一个bolt B时,应该发送给bolt B的那个task呢

有几种不同的分组策略,最简单的是shuffle grouping,它随机发给任何一个tuple,fields grouping能保证相同性质的东西发送到同一个task

可靠的消息处理

查看storm是如何保证消息不丢失的,以更深入的了解storm的可靠性API。

0 0
原创粉丝点击