Storm详解+案例

Storm (一)

storm的应用

  • 01 Apache Storm是什么

    实时计算和离线计算的区别:

    离线计算,一次计算很多条数据, 批次处理

    实时计算,数据被一条一条的计算, 实时收集、实时计算、实时展示

    Storm是一个流式计算框架

    Storm用来实时处理数据,特点:低延迟、高可用、分布式、可扩展、数据不丢失
    在这里插入图片描述

  • 02 Apache Storm 架构&编程模型&基本概念

在这里插入图片描述

在这里插入图片描述

  • 03 Apache Storm WordCount程序编写-创建工程及介绍Spout的三个方法

    创建maven工程,导入依赖

    <dependency>
        <groupId>org.apache.storm</groupId>
        <artifactId>storm-core</artifactId>
        <version>1.1.1</version>
    </dependency>
    

    创建数据流入源(spout)

    /**
     * 读取外部的文件,将一行一行的数据发送给下游的bolt
     * 类似于hadoop MapReduce中的inputformat
     */
    public class ReadFileSpout extends BaseRichSpout {
        private SpoutOutputCollector collector;
        private BufferedReader bufferedReader;
    
        /**
         * 初始化方法,类似于这个类的构造器,只被运行一次
         * 一般用来打开数据连接,打开网络连接。
         *
         * @param conf      传入的是storm集群的配置文件和用户自定义配置文件,一般不用。
         * @param context   上下文对象,一般不用
         * @param collector 数据输出的收集器,spout类将数据发送给collector,由collector发送给storm框架。
         */
        public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
            try {
                bufferedReader = new BufferedReader(new FileReader(new File("//root//zhangsan//wordcount.txt")));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            this.collector = collector;
        }
        /**
         * 下一个tuple,tuple是数据传送的基本单位。
         * 后台有个while循环一直调用该方法,每调用一次,就发送一个tuple出去
         */
        public void nextTuple() {
            String line = null;
            try {
                line = bufferedReader.readLine();
                if (line!=null){
                    collector.emit(Arrays.asList(line));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 声明发出的数据是什么
         *
         * @param declarer
         */
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("juzi"));
        }
    }
    
  • 05 Apache Storm WordCount程序编写-splitBolt进行单词切割

    /**
     * 输入:一行数据
     * 计算:对一行数据进行切割
     * 输出:单词及单词出现的次数
     */
    public class SplitBolt extends BaseRichBolt{
        private  OutputCollector collector;
        /**
         * 初始化方法,只被运行一次。
         * @param stormConf 配置文件
         * @param context 上下文对象,一般不用
         * @param collector 数据收集器
         */
        @Override
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
                this.collector = collector;
        }
        /**
         * 执行业务逻辑的方法
         * @param input 获取上游的数据
         */
        @Override
        public void execute(Tuple input) {
            // 获取上游的句子
            String juzi = input.getStringByField("juzi");
            // 对句子进行切割
            String[] words = juzi.split(" ");
            // 发送数据
            for (String word : words) {
                // 需要发送单词及单词出现的次数,共两个字段
                collector.emit(Arrays.asList(word,"1"));
            }
        }
        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word","num"));
        }
    }
    
  • 06 Apache Storm WordCount程序编写-单词计数

    /**
     * 输入:单词及单词出现的次数
     * 输出:打印在控制台
     * 负责统计每个单词出现的次数
     * 类似于hadoop MapReduce中的reduce函数
     */
    public class WordCountBolt extends BaseRichBolt {
        private Map<String, Integer> wordCountMap = new HashMap<String, Integer>();
    
        /**
         * 初始化方法
         *
         * @param stormConf 集群及用户自定义的配置文件
         * @param context   上下文对象
         * @param collector 数据收集器
         */
        @Override
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
            // 由于wordcount是最后一个bolt,所有不需要自定义OutputCollector collector,并赋值。
        }
        @Override
        public void execute(Tuple input) {
            //获取单词出现的信息(单词、次数)
            String word = input.getStringByField("word");
            String num = input.getStringByField("num");
            // 定义map记录单词出现的次数
            // 开始计数
            if (wordCountMap.containsKey(word)) {
                Integer integer = wordCountMap.get(word);
                wordCountMap.put(word, integer + Integer.parseInt(num));
            } else {
                wordCountMap.put(word, Integer.parseInt(num));
            }
            // 打印整个map
            System.out.println(wordCountMap);
        }
        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            // 不发送数据,所以不用实现。
        }
    }
    
  • 07 Apache Storm WordCount程序编写-本地运行及maven插件设置

    WordCountTopology类(main方法)

    /**
     * wordcount的驱动类,用来提交任务的。
     */
    public class WordCountTopology {
        public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException {
            // 通过TopologyBuilder来封装任务信息
            TopologyBuilder topologyBuilder = new TopologyBuilder();
    //        设置spout,获取数据
            topologyBuilder.setSpout("readfilespout",new ReadFileSpout(),2);
    //        设置splitbolt,对句子进行切割
            topologyBuilder.setBolt("splitbolt",new SplitBolt(),4).shuffleGrouping("readfilespout");
    //        设置wordcountbolt,对单词进行统计
            topologyBuilder.setBolt("wordcountBolt",new WordCountBolt(),2).shuffleGrouping("splitbolt");
    //        准备一个配置文件
            Config config = new Config();
    //        storm中任务提交有两种方式,一种方式是本地模式,另一种是集群模式。
    //        LocalCluster localCluster = new LocalCluster();
    //        localCluster.submitTopology("wordcount",config,topologyBuilder.createTopology());
            //在storm集群中,worker是用来分配的资源。如果一个程序没有指定worker数,那么就会使用默认值。
            config.setNumWorkers(2);
            //提交到集群
            StormSubmitter.submitTopology("wordcount1",config,topologyBuilder.createTopology());
        }
    }
    

    指定jdk版本插件

    		<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
    
  • 08 Apache Storm WordCount程序编写-程序运行的整体流程梳理

在这里插入图片描述

Storm集群搭建

  • 09 Apache Storm 集群管理-集群部署

    1. storm是依赖于zookeeper的,搭建storm集群前,必须先把zookeeper集群搭建好

    2. 上传解压storm安装包到指定目录

       tar -zxvf apache-storm-1.1.1.tar.gz -C ../services/
    
    1. 修改配置文件 storm.yaml

      storm.zookeeper.servers:
           - "node01"
           - "node02"
           - "node03"
      # 
      nimbus.seeds: ["node01", "node02", "node03"]
      
      storm.local.dir: "/export/data/stormdata" 
      ui.port: 8088
      supervisor.slots.ports:
          - 6700
          - 6701
          - 6702
          - 6703
      
      
    2. 将安装程序分发到其他机器

      scp -r apache-storm-1.1.1/ node02:/export/services/
      
      scp -r apache-storm-1.1.1/ node03:/export/services/
      
    3. 启动storm相关服务

      启动 nimbus进程(主节点)
      nohup bin/storm nimbus >/dev/null 2>&1 &
      启动supervisor(从节点)
      nohup bin/storm supervisor >/dev/null 2>&1 &
      启动web  UI
      nohup bin/storm ui >/dev/null 2>&1 &
      启动logViewer
      nohup bin/storm logviewer >/dev/null 2>&1 & 
      

      storm没有提供一键启动,需要自己手动编写一键启动脚本

    4. 访问stormUI界面

      访问地址

      http://xxxx:8088/

  • 10 Apache Storm 集群管理-编译代码并提交任务

    提交任务到集群

    bin/storm jar /export/services/storm.jar com.test.storm.MainTopology clusterStorm
    
  • 11 Apache Storm 集群管理-任务资源申请的基本单位Worker&Task

在这里插入图片描述

  • 12 Apache Storm 集群管理-任务提交过程及执行流程

在这里插入图片描述

在这里插入图片描述

  • 13 Apache Storm 集群管理-任务的worker&Task设置

在这里插入图片描述

  • 14 Apache Storm 集群管理-replication count及nimbus seeds节点说明

    nimbus seeds和我们启动的nimbus主节点的个数有关,每个任务都会在集群所有的nimbus主节点上备份一份

案例实战

  • 15 Apache Storm 案例实战-实时看板整体结构及模拟生产支付信息

    模拟生产了订单数据

在这里插入图片描述

  • 16 Apache Storm 案例实战-实时看板代码开发之集成KafkaSpout插件

    创建maven工程,导入依赖

     <dependencies>
            <dependency>
                <groupId>org.apache.storm</groupId>
                <artifactId>storm-core</artifactId>
                <version>1.1.1</version>
                <!-- 如果集群上提供了storm-core.jar。需要在编译的时候排除掉 -->
                <!--<scope>provided</scope>-->
            </dependency>
            <!--storm和kafka集成-->
            <!--  use new kafka spout code -->
            <dependency>
                <groupId>org.apache.storm</groupId>
                <artifactId>storm-kafka-client</artifactId>
                <version>1.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.kafka</groupId>
                <artifactId>kafka-clients</artifactId>
                <version>0.10.0.0</version>
            </dependency>
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.8.1</version>
            </dependency>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
    
    /**
     * 驱动类
     * 提交一个订单实时金额统计的任务
     */
    public class KanBanTopology {
        public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException {
            TopologyBuilder topologyBuilder = new TopologyBuilder();
    //        1.设置一个kafkaspout消费kafka集群中的数据
            KafkaSpoutConfig.Builder<String, String> builder = KafkaSpoutConfig.builder("node01:9092", "payment");
            builder.setGroupId("payment_storm_index");
            KafkaSpoutConfig<String, String> kafkaSpoutConfig = builder.build();
            topologyBuilder.setSpout("KafkaSpout", new KafkaSpout<String, String>(kafkaSpoutConfig), 3);
    //        2.设置解析json串的bolt
            topologyBuilder.setBolt("ParserPaymentBolt",new ParserPaymentBolt(),3).shuffleGrouping("KafkaSpout");
    //         3. 设置计算指标的bolt
            topologyBuilder.setBolt("PaymentIndexProcessBolt",new PaymentIndexProcessBolt(),3).shuffleGrouping("ParserPaymentBolt");
            // 4.得到一个真正的stormtopology对象,用来提交到集群
            StormTopology topology = topologyBuilder.createTopology();
            // 5.使用本地模式运行任务
            Config config = new Config();
            config.setNumWorkers(1);
            LocalCluster localCluster = new LocalCluster();
            localCluster.submitTopology("kanban",config,topology);
    //        StormSubmitter.submitTopology("kanban",config,topology);
        }
    }
    

在这里插入图片描述

  • 17 Apache Storm 案例实战-实时看板代码开发之使用Gson解析订单信息

    /**
     * 获取kafkaspout发送过来的数据,并解析成为一个javabean
     * 输入的json
     * 输出:java对象
     */
    public class ParserPaymentBolt extends BaseRichBolt {
        private  OutputCollector collector;
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
            this.collector = collector;
        }
        public void execute(Tuple input) {
            long start = System.currentTimeMillis();
            //1.获取从kafka集群中消费数据
            // 从input中获取值,有两种方式。getStringByField 和通过角标获取值
            String json = input.getStringByField("value");
    //        Object value1 = input.getValue(4);
    //        String value2 = input.getString(4);
            System.out.println("-------------");
            Gson gson = new Gson();
            Payment payment = gson.fromJson(json, Payment.class);
            // 在发送数据的时候,Arrays.asList得到一个list对象
            // 其实storm框架也封装一个类,让开发者快速的得到一个list。就是Values类
            collector.emit(new Values(payment));
            System.out.println(System.currentTimeMillis()-start);
        }
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("javaBean"));
        }
    }
    

在这里插入图片描述

  • 18 Apache Storm 案例实战-实时看板代码开发之订单人数、订单金额、订单数计算

    /**
     * 计算相关的指标
     * 计算那些指标?
     * 计算订单金额(payPrice字段的金额进行累加)、订单数(一条消息就是一个订单)、订单人数(一个消息就是一个人)
     * -------------指标口径的统一,在每个企业中都不一样。作为开发者,一定要找产品经理或者提需求的人讨论明白。
     * 指标数据存放到哪里?
     * --------------存放到redis
     */
    public class PaymentIndexProcessBolt extends BaseRichBolt {
        private Jedis jedis = null;
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
    //        jedis = new Jedis("redis",6379);
            jedis = new Jedis("192.168.40.167",6379);
        }
        public void execute(Tuple input) {
            // 获取上游发送的值
            Payment value = (Payment) input.getValue(0);
            //  计算订单金额(payPrice字段的金额进行累加)、订单数(一条消息就是一个订单)、订单人数(一个消息就是一个人)
            jedis.incrBy("price", value.getPayPrice());
            jedis.incrBy("orderNum",1);
            jedis.incrBy("orderUser",1);
            // 计算每个品类的订单数,订单人数,订单金额
            // 返回的是三品的一级品类,二级品类,三级品类
            String categorys = value.getCatagorys();
            String[] split = categorys.split(",");
            //102,144,114
            for(int i=0;i<split.length;i++){
                //price:1:102
                //price:2:144
                //price:3:144
                jedis.incrBy("price:"+(i+1)+":"+split[i], value.getPayPrice());
                jedis.incrBy("orderNum:"+(i+1)+":"+split[i],1);
                jedis.incrBy("orderUser:"+(i+1)+":"+split[i],1);
            }
            // 计算商品属于哪个产品线
    //        jedis.incrBy("price:cpxid:"+split[i], value.getPayPrice());
            //计算每个店铺的订单人数,订单金额,订单数
            jedis.incrBy("price:shop:"+value.getShopId(), value.getPayPrice());
            jedis.incrBy("orderNum:shop:"+value.getShopId(),1);
            jedis.incrBy("orderUser:shop:"+value.getShopId(),1);
            //计算每个商品的订单人数,订单金额,订单数
            jedis.incrBy("price:pid:"+value.getProductId(), value.getPayPrice());
            jedis.incrBy("orderNum:pid:"+value.getProductId(),1);
            jedis.incrBy("orderUser:pid:"+value.getProductId(),1);
        }
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
        }
    }
    

在这里插入图片描述

  • 19 Apache Storm 案例实战-实时看板代码开发之 程序的worker&Task数量设置

    根据所处理对的数据大小,以及kafka的消费者负载均衡策略,设置程序的worker和task数

  • 20 Apache Storm 案例实战-实时看板代码打包运行(maven的provide作用域说明)

    打包插件

         <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
    						  <!--设置驱动-->
                              <mainClass>cn.itcast.realtime.storm.kanban.KanBanTopology</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    

    标签值得使用,说明:

     <scope>provided</scope>
    目前<scope>可以使用5个值:
    	* compile,缺省值,适用于所有阶段,会随着项目一起发布。
    	* provided,表示打包时不需要该jar包,本地运行时需要。
    	* runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。
    	* test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
    	* system,类似provided,需要显式提供包含依赖的jar,Maven不会在Repository中查找它。
               
    
  • 21 Apache Storm 案例实战-实时看板业务问题扩展

    实现商品的一级,二级,三级分类

    每个品类,每个产品线,每个店铺,每个商品分别的实时成交情况

Storm 一键启动脚本扩展

  1. storm集群一键启动脚本

    source /etc/profile
    nohup storm nimbus >/dev/null 2>&1 &
    nohup storm ui >/dev/null 2>&1 &
    cat /export/servers/storm/bin/slave | while read line
    do
    {
     echo $line
     ssh $line "source /etc/profile;nohup storm supervisor >/dev/null 2>&1 &"
    }&
    wait
    done 
    
  2. storm集群一键停止脚本

    source /etc/profile
    jps | awk '{ if( $2 == "nimbus" || $2 == "supervisor" ||  $2 == "core" ) print $1 }' |xargs kill -s 9
    cat /export/script/slaves | while read line
    do
    {
     echo $line
     ssh $line "source /etc/profile;jps |grep Supervisor |cut -c 1-4 |xargs kill -s 9"
    }&
    wait
    done 
    
  3. slave文件

    node02
    node03
    

Storm的动态修改并行参数

  • 运行命令

    storm rebalance mytopology -n 3 -e mySpout=5 -e splitBolt=6 -e countBolt=8
    
  • 参数介绍

    mytopology 我们在storm集群提交任务时,所取的任务名

    -n 表示要设置的worker数 后面跟上要具体设置的数值

    -e 表示要设置的executor数后面跟上Spout/Bolt的类名 id=具体数值

    一定要注意:重新调整的时候=号两边不要有空格
    在这里插入图片描述

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【课程大纲】 01.Storm项目实战课程大纲 02.CDH5搭建之CM5安装部署 03.CDH5搭建和CM界面化集群管理 04.Hadoop、HBase、Zookeeper集群管理和角色分配 05.Kafka基础知识和集群搭建 06.Kafka基本操作和最优设置 07.Kafka Java API 简单开发测试 08.storm-kafka 详解和实战案例 09.S图表框架HighCharts介绍 10.HBase快速入门 11.基于HBase的Dao基类和实现类开发一 12.基于HBase的Dao基类和实现类开发二 13.项目1-地区销售额-需求分析和架构设计 14.项目1-地区销售额-Spout融合Kafka Consumer及线程安全测试 15.项目1-地区销售额-Bolt业务逻辑处理一 16.项目1-地区销售额-优化Bolt支持重启及结果数据核查 17.项目1-地区销售额-HighCharts图表开发一及Web端架构设计 18.项目1-地区销售额-HTTP长链接实现实时推送 19.项目1-地区销售额-HighCharts图表开发二及jquery运用 20.项目1-地区销售额-Web端完善和细节优化 21.项目1-地区销售额-项目发布及总结 22.项目1-地区销售额-项目需求分析和分区Trident Spout开发 23.项目1-地区销售额-Trident代码开发一 24.项目1-地区销售额-Trident代码开发二 25.项目1-地区销售额-基于HBase存储的State运用 26.项目2-省份销售排行-双纵轴HighCharts图表开发一 27.项目2-省份销售排行-双纵轴HighCharts图表开发二 28.项目2-省份销售排行-双纵轴HighCharts图表开发三 29.项目2-省份销售排行-前台和图表交互开发和Top N实现 30.项目2-省份销售排行-Top N展示优化和项目开发思路总结 31.项目2-效果展示及项目3需求分析梳理 32.项目3-非跳出UV-Storm topology开发一 33.项目3-非跳出UV-Storm topology开发二 34.项目3-非跳出UV-Web端Servlet开发 35.项目3-非跳出UV-Web端Highcharts图表开发 36.项目3-非跳出UV-项目效果调试 37.项目3-非跳出UV-项目整体运行 38.项目3-非跳出UV-升级图表增加柱图一 39.项目3-非跳出UV-升级图表增加柱图二 40.JStorm介绍 41.会员问题收集和解答

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值