流式计算--storm3(Storm单词技术案例)

    功能说明:设计一个topology,来实现对文档里面的单词出现的频率进行统计。本篇博客是在storm概念讲解storm集群搭建的基础上来的

  1.创建一个maven项目:

        添加以来如下: 

 <dependency>
                <groupId>org.apache.storm</groupId>
                <artifactId>storm-core</artifactId>
                <version>1.0.6</version>
                <!--storm集群里面已经有jar包,所以添加下面的provided表示已提供jar包,所以打包的时候就要剔除相应的jar包,现在跑本地需要注释掉-->
                <!--<scope>provided</scope>-->
            </dependency>

   创建一个MySpout类继承BaseRichSpout类,用于接收外部数据源的数据

package com.wx.storm1;

import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;

import java.util.Map;

public class MySpout extends BaseRichSpout {

    SpoutOutputCollector outputCollector;
    //初始化的方法,该方法调用一次,主要由Storm框架传入SpoutOutputCollector
    public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
             this.outputCollector=spoutOutputCollector;
    }
    //storm 框架在 while(true) 调用nextTuple方法
    public void nextTuple() {
        outputCollector.emit(new Values("I love you,wang zu xian,my names Mr.Wang"));
    }
    //消息源可以发送多条消息流stream,多条消息流可以理解为多种类型的数据
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("word"));
    }
}

 

创建一个MyBolt继承于BaseRichBolt,主要是分割单词,得到的单词计数输出

  

package com.wx.storm1;

import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IBasicBolt;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.IWindowedBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

import java.util.Map;

public class MyBolt extends BaseRichBolt{
    OutputCollector outputCollector;
    //初始化方法
    public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
        this.outputCollector=outputCollector;
    }
    //被storm框架 while(true) 循环调用  传入参数tuple
    public void execute(Tuple tuple) {
        //这里将单词分割,得到的单词计数输出
        String string = tuple.getString(0);
        String[] split = string.split(" ");
        for (String val:split)
        {
            outputCollector.emit(new Values(val,1));
        }
    }
    //输出到下一个bolt
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("word","num"));
    }
}

  创建一个MyBoltCount继承于BaseRichBolt ,主要是对相同的单词做统计

package com.wx.storm1;

import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IBasicBolt;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.IWindowedBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Tuple;

import java.util.HashMap;
import java.util.Map;

public class MyBoltCount extends BaseRichBolt {
    OutputCollector outputCollector;
    Map<String,Integer> map=new HashMap<String, Integer>();
    //初始化方法
    public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
        this.outputCollector=outputCollector;
    }
    //被storm框架 while(true) 循环调用  传入参数tuple
    public void execute(Tuple tuple) {
          //这里就将相同的单词统计出来,然后输出
        String word = tuple.getString(0);
        Integer num = tuple.getInteger(1);
        if(!map.containsKey(word))
        {
            map.put(word,num);
        }
        else
        {
            Integer count=map.get(word);
            map.put(word,num+count);
        }
        System.out.println("count:"+map);
    }

    //这个bolt就是尽头了,不输出
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {

    }
}

  创建一个拓扑来分配任务:
  

package com.wx.storm1;
import org.apache.storm.Config;
import org.apache.storm.StormSubmitter;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;

public class WordCountStrom {
     public static  void  main(String[] args) throws  Exception
     {
         //Storm计算wordcount
         //1.创建一个TopologyBuilder
         TopologyBuilder topologyBuilder = new TopologyBuilder();
         //指定Spout的类和需要task的数量,task的数量即线程的数量
         topologyBuilder.setSpout("myspout",new MySpout(),2);
         //指定需要的第一级bolt的类和task的数量
         topologyBuilder.setBolt("mybolt1",new MyBolt(),2).shuffleGrouping("myspout"); //随机函数分组
         topologyBuilder.setBolt("mybolt2",new MyBoltCount(),4).fieldsGrouping("mybolt1",new Fields("word"));//hash取模分组

         //2.创建一个configuration,用来指定当前topology 需要的worker的数量
         Config config=new Config();
         config.setNumWorkers(3);

         //3.提交任务  -----两种模式 本地模式和集群模式
         //StormSubmitter.submitTopology("wordcount",config,topologyBuilder.createTopology());
         LocalCluster localCluster = new LocalCluster();
         localCluster.submitTopology("wordcount",config,topologyBuilder.createTopology());

     }
}

   测试结果:
 

如果要提交到集群运行:
 首先需要修改pom文件,表示storm集群中已经提供jar包

   

其次提交拓扑的任务修改为集群模式

 

在idea中进行打包:双击package打包成功:

打的jar包在target目录下:ok ,上传至集群,准备运行

执行运行

 

集群的拓扑途中就有了:

 

使用命令把他kill 掉:storm kill wordcount  

  

可以查看日志:cd /export/servers/storm/logs/

  

2.Storm常用操作命令

有许多简单且有用的命令可以用来管理拓扑,它们可以提交、杀死、禁用、再平衡拓扑。

1.提交任务命令格式:storm jar 【jar路径】 【拓扑包名.拓扑类名】 【拓扑名称】

bin/storm jar examples/storm-starter/storm-starter-topologies-0.9.6.jar storm.starter.WordCountTopology wordcount

2.杀死任务命令格式:storm kill 【拓扑名称】 -w 10(执行kill命令时可以通过-w [等待秒数]指定拓扑停用以后的等待时间)

storm kill topology-name -w 10

3.停用任务命令格式:storm deactivte  【拓扑名称】

storm deactivte topology-name

我们能够挂起或停用运行中的拓扑。当停用拓扑时,所有已分发的元组都会得到处理,但是spouts的nextTuple方法不会被调用。销毁一个拓扑,可以使用kill命令。它会以一种安全的方式销毁一个拓扑,首先停用拓扑,在等待拓扑消息的时间段内允许拓扑完成当前的数据流。

4.启用任务命令格式:storm activate【拓扑名称】

        storm activate topology-name

5.重新部署任务命令格式:storm rebalance  【拓扑名称】

        storm rebalance topology-name

        再平衡使你重分配集群任务。这是个很强大的命令。比如,你向一个运行中的集群增加了节点。再平衡命令将会停用拓扑,然后在相应超时时间之后重分配工人,并重启拓扑。

 3.执行原理图(Mr.Mao的图)

     这里我们stream grouping的分组方式是按字段进行分组,比如按userid来分组,具有同样userid的tuple会被分到相同的Bolts里的一个task,而不同的userid则会被分配到不同的bolts里的task。

  

4.Stream Grouping详解

  

Storm里面有7种类型的stream grouping

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

  5.问题(Mr.Mao的图)

      1.集群如何启动,任务如何执行?

         

     2、集群如何通信:集群架构中的各个模块是如何通信的?拓扑程序中的各个Task是如何通信的?

         nimbus与supervisor之间是通过zk进行通信的

         不同机器上的worker是基于网络io的socket通信(netty)

          worker内部是基于县城的通信,线程于线程通信

          

   3.如何保证消息的不丢失   ack-fail机制如何实现的?

    

  4.storm 启动流程分析

  

流式计算一般架构图

下面会学习kafka....

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值