Storm自学1

一、Storm 简介  

      Storm是一个开源的分布式实时计算系统,可以简单、可靠的处理大量的数据流。被称作“实时的hadoop”。Storm有很多使用场景:如实时分析,在线机器学习,持续计算, 分布式RPCETL等等。Storm支持水平扩展,具有高容错性,保证每个消息都会得到处理,而且处理速度很快(在一个小集群中,每个结点每秒可以处理 数以百万计的消息)。Storm的部署和运维都很便捷,而且更为重要的是可以使用任意编程语言来开发应用。

二、Storm 体系结构

在深入理解Storm之前,需要了解一些概念:

  1. Topologies : 拓扑,也俗称一个任务
  2. Spouts : 拓扑的消息源
  3. Bolts : 拓扑的处理逻辑单元
  4. tuple:消息元组
  5. Streams : 流
  6. Stream groupings :流的分组策略
  7. Tasks : 任务处理单元
  8. Executor :工作线程
  9. Workers :工作进程
  10. Configuration topology的配置

Storm中的NimbusSupervisor

        NimbusSupervisor之间的所有协调工作都是通过Zookeeper集群完成。Nimbus进程和Supervisor进程都是快速失败(fail-fast)和无状态的。所有的状态要么在zookeeper里面, 要么在本地磁盘上。这也就意味着你可以用kill -9来杀死NimbusSupervisor进程, 然后再重启它们,就好像什么都没有发生过。这个设计使得Storm异常的稳定。

Storm中的Topologies

       一个topologyspoutsbolts组成的图, 通过stream groupings将图中的spoutsbolts连接起来,如下图:

Storm中的Stream

       消息流streamstorm里的关键抽象; 一个消息流是一个没有边界的tuple序列, 而这些tuple序列会以一种分布式的方式并行地创建和处理;通过对stream中tuple序列中每个字段命名来定义stream 在默认的情况下,tuple的字段类型可以是:integerlongshortbytestringdoublefloatbooleanbyte array 可以自定义类型(只要实现相应的序列化器)。

Storm中的Spouts

       消息源spoutStorm里面一个topology里面的消息生产者; 一般来说消息源会从一个外部源读取数据并且向topology里面发出消息:tuple Spouts可以是可靠的也可以是不可靠的:如果这个tuple没有被storm成功处理,可靠的消息源spouts可以重新发射一个tuple, 但是不可靠的消息源spouts一旦发出一个tuple就不能重发了;消息源可以发射多条消息流stream:使用OutputFieldsDeclarer.declareStream来定义多个stream 然后使用SpoutOutputCollector来发射指定的stream

Storm中的Bolts

       所有的消息处理逻辑被封装在bolts里面; Bolts可以做很多事情:过滤,聚合,查询数据库等等。 Bolts可以简单的做消息流的传递,也可以通过多级Bolts的组合来完成复杂的消息流处理;比如求TopN、聚合操作等(如果要把这个过程做得更具有扩展性那么可能需要更多的步骤)。

  • Bolts可以发射多条消息流:使用OutputFieldsDeclarer.declareStream定义stream 使用OutputCollector.emit来选择要发射的stream
  • Bolts的主要方法是execute 它以一个tuple作为输入,使用OutputCollector来发射tuple通过调用OutputCollectorack方法,以通知这个tuple的发射者spout
  • Bolts一般的流程: 处理一个输入tuple,  发射0个或者多个tuple, 然后调用ack通知storm自己已经处理过这个tuple了; storm提供了一个IBasicBolt会自动调用ack

Storm中的Stream groupings

       定义一个topology的关键一步是定义每个bolt接收什么样的流作为输入; stream grouping就是用来定义一个stream应该如何分配数据给bolts

Storm里面有7种类型的stream grouping

  1. Shuffle Grouping——随机分组, 随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同;
  2. Fields Grouping——按字段分组, 比如按userid来分组, 具有同样useridtuple会被分到相同的Bolts里的一个task, 而不同的userid则会被分配到不同的bolts里的task
  3. All Grouping——广播发送,对于每一个tuple,所有的bolts都会收到;
  4. Global Grouping——全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task
  5. Non Grouping——不分组,这个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果, 有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行;
  6. Direct Grouping——直接分组, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。 只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。 消息处理者可以通过TopologyContext来获取处理它的消息的taskid OutputCollector.emit方法也会返回taskid);
  7. Local or shuffle grouping——如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。否则,和普通的Shuffle Grouping行为一致。

 Topology 与 Mapreduce的 一个关键的区别是: 一个MapReduce job最终会结束, 而一个topology永远会运行(除非你手动kill掉)

三、Storm topology supovisor  worker

1、Nimbus 与 ResourManager

       在Storm的集群里面有两种节点: 控制节点(master node)和工作节点(worker node)。控制节点上面运行一个叫Nimbus后台程序,它的作用类似Hadoop里面的JobTrackerNimbus负责在集群里面分发代码,分配计算任务给机器, 并且监控状态。

Supervisor (worker进程)与NodeManager(YarnChild)

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

      NimbusSupervisor之间的所有协调工作都是通过Zookeeper集群完成。Nimbus进程和Supervisor进程都是快速失败(fail-fast)和无状态的。所有的状态要么在zookeeper里面, 要么在本地磁盘上。这也就意味着你可以用kill -9来杀死NimbusSupervisor进程, 然后再重启它们,就好像什么都没有发生过。这个设计使得Storm异常的稳定。

 

       一个topology可能会在一个或者多个worker(工作进程)里面执行; 每个worker是一个物理JVM并且执行整个topology的一部分; 比如,对于并行度是300topology来说,如果我们使用50个工作进程来执行,那么每个工作进程会处理其中的6tasks Storm会尽量均匀的工作分配给所有的worker

      每一个spoutbolt会被当作很多task在整个集群里执行 ;每一个executor对应到一个线程,在这个线程上运行多个task ;stream grouping则是定义怎么从一堆task发射tuple到另外一堆task ;可以调用TopologyBuilder类的setSpoutsetBolt来设置并行度(也就是有多少个task)。

Storm 安装部署

部署Storm集群需要依次完成的安装步骤:

       1.安装jdk6及以上版本;

  2. 搭建Zookeeper集群;

  3. 安装Storm依赖库;

  4. 下载并解压Storm发布版本;

  5. 修改storm.yaml配置文件;

  6. 启动Storm各个后台进程。

五、Storm 常用命令

1、启动nimbus后台程序
     命令格式:storm nimbus

2、启动supervisor后台程序
     命令格式:storm supervisor

3、启动ui服务
      命令格式:storm ui

4、提交Topologies
      命令格式:storm jar 【jar路径】 【拓扑包名.拓扑类名】【stormIP地址】【storm端口】【拓扑名称】【参数
      eg
      storm jar /home/storm/storm-starter.jar storm.starter.WordCountTopology wordcountTop;
      #提交storm-starter.jar到远程集群,并启动wordcountTop拓扑。

5、停止Topologies

      查看当前运行的topo: storm list
      命令格式:
storm kill 【拓扑名称
      样例:storm kill wordcountTop
      #杀掉wordcountTop拓扑。

六、Storm 编程接口

1、Spouts

        SpoutStream的消息产生源, Spout组件的实现可以通过继承BaseRichSpout类或者其他*Spout类来完成,也可以通过实现IRichSpout接口来实现。 需要根据情况实现Spout类中重要的几个方法有:

open方法

       当一个Task被初始化的时候会调用此open方法。一般都会在此方法中对发送Tuple的对象SpoutOutputCollector和配置对象TopologyContext初始化。

示例如下:

  public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {

  this._collector = collector;

}

getComponentConfiguration方法

示例如下:

public Map<String, Object> getComponentConfiguration() {

      if(!_isDistributed) {

  Map<String, Object> ret = new HashMap<String, Object>();

   ret.put(Config.TOPOLOGY_MAX_TASK_PARALLELISM, 3);

   return ret;10 11

      } else {

  return null;

     }

}

      这里便是设置了Topology中当前Component的线程数量上限。

• nextTuple方法

这是Spout类中最重要的一个方法。发射一个TupleTopology都是通过这个方法来实现的。

示例如下:

public void nextTuple() {

     Utils.sleep(100);

     final String[] words = new String[] {"twitter","facebook","google"};

     final Random rand = new Random();

     final String word = words[rand.nextInt(words.length)];

     _collector.emit(new Values(word));

    这里便是从一个数组中随机选取一个单词作为Tuple,然后通过_collector发送到Topology

• declareOutputFields方法

此方法用于声明当前SpoutTuple发送流。

Stream流的定义是通过OutputFieldsDeclare.declare方法完成的,其中的参数包括了发送的域Fields

示例如下:

public void declareOutputFields(OutputFieldsDeclarer declarer) {

  declarer.declare(new Fields("word"));

 }

另外,除了上述几个方法之外,还有ackfailclose方法等;

Storm在监测到一个Tuple被成功处理之后会调用ack方法,处理失败会调用fail方法; 这两个方法在BaseRichSpout等类中已经被隐式的实现了。  

2、Bolts

     Bolt类接收由Spout或者其他上游Bolt类发来的Tuple,对其进行处理。Bolt组件的实现可以通过继承BasicRichBolt类或者IRichBolt接口来完成。

    Bolt类需要实现的主要方法有:

prepare方法

此方法和Spout中的open方法类似,为Bolt提供了OutputCollector,用来从Bolt中发送TupleBoltTuple的发送可以在prepare方法中、execute方法中、cleanup等方法中进行,一般都是些在execute中。

    示例如下:

public void prepare(Map conf, TopologyContext context, OutputCollector collector) {

   this. _collector = collector;

}

getComponentConfiguration方法

Spout类一样,在Bolt中也可以有getComponentConfiguration方法。

    示例如下:

public Map<String, Object> getComponentConfiguration() {

     Map<String, Object> conf = new HashMap<String, Object>();

     conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS,     

     emitFrequencyInSeconds);

     return conf;

 } 

    此例定义了从系统组件“_system”的“_tick”流中发送Tuple到当前Bolt的频率,当系统需要每隔一段时间执行特定的处理时,就可以利用这个系统的组件的特性来完成。

execute方法

       这是Bolt中最关键的一个方法,对于Tuple的处理都可以放到此方法中进行。具体的发送也是在execute中通过调用emit方法来完成的。

有两种情况,一种是emit方法中有两个参数,另一个种是有一个参数。

(1)emit有一个参数:此唯一的参数是发送到下游BoltTuple,此时,由上游发来的旧的Tuple在此隔断,新的Tuple和旧的Tuple不再属于同一棵Tuple树。新的Tuple另起一个新的Tuple树。

(2)emit有两个参数:第一个参数是旧的Tuple的输入流,第二个参数是发往下游Bolt的新的Tuple流。此时,新的Tuple和旧的Tuple是仍然属于同一棵Tuple树,即,如果下游的Bolt处理Tuple失败,则会向上传递到当前Bolt,当前Bolt根据旧的Tuple流继续往上游传递,申请重发失败的Tuple。保证Tuple处理的可靠性。

declareOutputFields方法

    用于声明当前Bolt发送的Tuple中包含的字段,和Spout中类似。

    示例如下:

public void declareOutputFields(OutputFieldsDeclarer declarer) {

   declarer.declare(new Fields("obj", "count",   "actualWindowLengthInSeconds"));

 } 

 此例说明当前Bolt类发送的Tuple包含了三个字段:"obj", "count", "actualWindowLengthInSeconds"

3、topology

七、Storm 运行机制

(1)Storm提交后,会把代码首先存放到Nimbus节点的inbox目录下,之后,会把当前Storm运行的配置生成一个stormconf.ser文件放到Nimbus节点的stormdist目录中,在此目录中同时还有序列化之后的Topology代码文件;

(2)在设定Topology所关联的SpoutsBolts时,可以同时设置当前SpoutBoltexecutor数目和task数目,默认情况下,一个Topologytask的总和是和executor的总和一致的。之后,系统根据worker的数目,尽量平均的分配这些task的执行。worker在哪个supervisor节点上运行是由storm本身决定的;

(3)任务分配好之后,Nimbes节点会将任务的信息提交到zookeeper集群,同时在zookeeper集群中会有workerbeats节点,这里存储了当前Topology的所有worker进程的心跳信息;

(4)Supervisor节点会不断的轮询zookeeper集群,在zookeeperassignments节点中保存了所有Topology的任务分配信息、代码存储目录、任务之间的关联关系等,Supervisor通过轮询此节点的内容,来领取自己的任务,启动worker进程运行;

(5)一个Topology运行之后,就会不断的通过Spouts来发送Stream流,通过Bolts来不断的处理接收到的Stream流,Stream流是无界的。

最后一步会不间断的执行,除非手动结束Topology

Topology中的Stream处理时的方法调用过程如下:

有几点需要说明的地方:

   (1)每个组件(Spout或者Bolt)的构造方法和declareOutputFields方法都只被调用一次。

   (2)open方法、prepare方法的调用是多次的。入口函数中设定的setSpout或者setBolt里的并行度参数指的是executor的数目,是负责运行组件中的task的线程 的数目,此数目是多少,上述的两个方法就会被调用多少次,在每个executor运行的时候调用一次。相当于一个线程的构造方法。

   (3)nextTuple方法、execute方法是一直被运行的,nextTuple方法不断的发射TupleBoltexecute不断的接收Tuple进行处理。只有这样不断地运行,才会产生无界的Tuple流,体现实时性。相当于线程的run方法。

   (4)在提交了一个topology之后,Storm就会创建spout/bolt实例并进行序列化。之后,将序列化的component发送给所有的任务所在的机器(Supervisor节 点),在每一个任务上反序列化component

   (5)SpoutBolt之间、BoltBolt之间的通信,是通过zeroMQ的消息队列实现的。

   (6)上图没有列出ack方法和fail方法,在一个Tuple被成功处理之后,需要调用ack方法来标记成功,否则调用fail方法标记失败,重新处理这个Tuple

通过在Nimbus节点利用如下命令来终止一个Topology的运行:

bin/storm kill topologyName

kill之后,可以通过UI界面查看topology状态,会首先变成KILLED状态,在清理完本地目录和zookeeper集群中的和当前Topology相关的信息之后,此Topology就会彻底消失。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值