Storm入门小Dome

Storm如何小Dome(本地实现)

1.什么是Apache Storm?
Apache Storm是一个分布式实时大数据处理系统。Storm设计用于在容错和水平可扩展方法中处理大量数据。它是一个流数据框架,具有最高的摄取率。虽然Storm是无状态的,它通过Apache ZooKeeper管理分布式环境和集群状态。它很简单,您可以并行地对实时数据执行各种操作。
2.Apache Storm核心概念
Apache Storm从一端读取​​实时数据的原始流,并将其传递通过一系列小处理单元,并在另一端输出处理/有用的信息。
在这里插入图片描述
现在让我们仔细看看Apache Storm的组件
1.Tuple------Tuple是Storm中的主要数据结构。它是有序元素的列表。默认情况下,Tuple支持所有数据类型。通常,它被建模为一组逗号分隔的值,并传递到Storm集群。
2.Stream----流是元组的无序序列。
3.Spouts----流的源。通常,Storm从原始数据源(如Twitter Streaming API,Apache Kafka队列,Kestrel队列等)接受输入数据。否则,您可以编写spouts以从数据源读取数据。“ISpout”是实现spouts的核心接口,一些特定的接口是IRichSpout,BaseRichSpout,KafkaSpout等。
4.Bolts —Bolts是逻辑处理单元。Spouts将数据传递到Bolts和Bolts过程,并产生新的输出流。Bolts可以执行过滤,聚合,加入,与数据源和数据库交互的操作。Bolts接收数据并发射到一个或多个Bolts。 “IBolt”是实现Bolts的核心接口。一些常见的接口是IRichBolt,IBasicBolt等。

3.Storm 入门word-count实例
本例的实现逻辑
在这里插入图片描述
1.创建一个maven工程 storm-demo ,引入相关依赖

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

2.常见数据源

package com.hzm;

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 org.apache.storm.utils.Utils;

import java.util.Map;

/**
 * @Author:huangzhimin
 * @Date:2020/7/1
 * @描述:storm的数据源
 **/
public class SentenceSpout extends BaseRichSpout {
    //BaseRichSpout是ISpout接口和IComponent接口的简单实现,接口对用不到的方法提供了默认的实现
    private SpoutOutputCollector collector;
    //模拟数据源
    public String [] sentenceArray  = {
            "my name is huangzhimi",
            "i am a IT worker",
            "i like this job",
            "i am working in nanjin"
    };
    //每次只发布一个句话,故设置索引
    public int index = 0;
    /**
     * sout 初始化是被调用
     * @param map 为此spout提供storm配置。
     * @param topologyContext  提供有关拓扑中的spout位置,其任务ID,输入和输出信息的完整信息
     * @param spoutOutputCollector 使我们能够发出将由bolts处理的元组。
     *  在本实例中无需初始化实例,只需保存spoutOutputCollector 实例即可
     */
    @Override
    public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
        this.collector = spoutOutputCollector;
    }

    /**
     * 通过收集器发出生成的数据
     * nextTuple 是spout 输出数据的核心
     */
    @Override
    public void nextTuple() {
        //发射出第一句话
        this.collector.emit(new Values(sentenceArray[index]));
        //发射出下一句话
        index ++;
        //避免出数据越界
        if(index >= sentenceArray.length){
            index=0;
        }
        Utils.sleep(1);
    }

    /**
     *通过该方法告诉storm 集群 spout 抛出那些字段
     * @param outputFieldsDeclarer
     */
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("sentence"));
    }
}

2.创建第一个bolt 用于拆分语句

package com.hzm;

import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
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;

/**
 * @Author:huangzhimin
 * @Date:2020/7/1
 * @描述:流处理逻辑1,拆分数据
 **/
public class SplitBolt extends BaseRichBolt {
    private OutputCollector collector;
    //BaseRichBolt是IComponent和IBolt接口的实现

    /**为bolt提供要执行的环境。执行器将运行此方法来初始化spout。
     * prepare()方法类似于ISpout 的open()方法。
     * 这个方法在blot初始化时调用,可以用来准备bolt用到的资源,比如数据库连接
     * 本例子和SentenceSpout类一样,SplitSentenceBolt类不需要太多额外的初始化
     * @param map
     * @param topologyContext
     * @param outputCollector
     */
    @Override
    public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
        this.collector = outputCollector;
    }

    /**
     * 处理单个元组的输入
     * @param tuple
     */

    @Override
    public void execute(Tuple tuple) {
        String value = tuple.getStringByField("sentence");
        System.out.println("value=======>"+value);
        String [] wordArray = value.split(" ");
        for (int i = 0; i < wordArray.length; i++) {
            System.out.println(wordArray[i]);
            this.collector.emit(new Values(wordArray[i]));
        }
    }

    /**
     * 声明元组的输出模式。
     * @param outputFieldsDeclarer
     */
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("word"));
    }
}

3.创建第2个bolt 进行统计

package com.hzm;

import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
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.HashMap;
import java.util.Map;

/**
 * @Author:huangzhimin
 * @Date:2020/7/1
 * @描述:流处理逻辑,数据求和
 **/
public class CountBolt extends BaseRichBolt {
    private OutputCollector collector;
    private Map<String,Integer> wordCoutMap ;

    /**
     * 和splitBolt 同理
     * @param map
     * @param topologyContext
     * @param outputCollector
     */
    @Override
    public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
        this.collector = outputCollector;
        this.wordCoutMap = new HashMap<>();
    }

    /**
     * 处理数据,对数据进行求和
     * @param tuple
     */
    @Override
    public void execute(Tuple tuple) {
        String word = tuple.getStringByField("word");
        Integer count = this.wordCoutMap.get(word);
        if(count == null){
            //初始化
            count = 0;
        }
        count ++;
        wordCoutMap.put(word,count);
        this.collector.emit(new Values(word,count));
    }

    /**
     * 将数据发射出去
     * @param outputFieldsDeclarer
     */
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("word","count"));
    }
}

4.创建最终的处理逻辑

package com.hzm;

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

import java.util.*;

/**
 * @Author:huangzhimin
 * @Date:2020/7/1
 * @描述:逻辑处理3,形成统计报告
 **/
public class ReportBolt extends BaseRichBolt {
    private Map<String,Integer> wordCoutMap ;
    @Override
    public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
        this.wordCoutMap = new HashMap<>();
    }

    @Override
    public void execute(Tuple tuple) {
        String word = tuple.getStringByField("word");
        Integer count = tuple.getIntegerByField("count");
        wordCoutMap.put(word,count);
        System.out.println("当前数据为====>"+wordCoutMap);

    }
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        //这是最后一个处理逻辑,不需要在抛出数据了
    }
    /**
     * cleanup是IBolt接口中定义
     * Storm在终止一个bolt之前会调用这个方法
     * 本例我们利用cleanup()方法在topology关闭时输出最终的计数结果
     * 通常情况下,cleanup()方法用来释放bolt占用的资源,如打开的文件句柄或数据库连接
     * 但是当Storm拓扑在一个集群上运行,IBolt.cleanup()方法不能保证执行(这里是开发模式,生产环境不要这样做)。
     */
    @Override
    public void cleanup(){
        System.out.println("---------- FINAL COUNTS -----------");
        //从map中取值
        Iterator<String> iter = wordCoutMap.keySet().iterator();
        while(iter.hasNext()){
            String key=iter.next();
            //存放同一类型的元素
            Integer num = wordCoutMap.get(key);
            System.out.println("key:"+key+" num ="+num);
        }
        System.out.println("----------------------------");
    }

}

5.形成拓扑结构

package com.hzm;

import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;
import org.apache.storm.utils.Utils;

/**
 * @Author:huangzhimin
 * @Date:2020/7/1
 * @描述:用于本地测试流的逻辑
 **/
public class Topology {
    private static final String SENTENCE_SPOUT_ID = "sentence-spout";
    private static final String SPLIT_BOLT_ID = "split-bolt";
    private static final String COUNT_BOLT_ID = "count-bolt";
    private static final String REPORT_BOLT_ID = "report-bolt";
    private static final String TOPOLOGY_NAME = "word-count-topology";

    public static void main(String[] args) {
//System.out.println( "Hello World!" );
        //实例化spout和bolt

        SentenceSpout spout = new SentenceSpout();
        SplitBolt SplitBolt = new SplitBolt();
        CountBolt countBolt = new CountBolt();
        ReportBolt reportBolt = new ReportBolt();

        TopologyBuilder builder = new TopologyBuilder();//创建了一个TopologyBuilder实例

        //TopologyBuilder提供流式风格的API来定义topology组件之间的数据流

        //builder.setSpout(SENTENCE_SPOUT_ID, spout);//注册一个sentence spout

        //设置两个Executeor(线程),默认一个
        builder.setSpout(SENTENCE_SPOUT_ID, spout,2);

        // SentenceSpout --> SplitSentenceBolt

        //注册一个bolt并订阅sentence发射出的数据流,shuffleGrouping方法告诉Storm要将SentenceSpout发射的tuple随机均匀的分发给SplitSentenceBolt的实例
        //builder.setBolt(SPLIT_BOLT_ID, SplitBolt).shuffleGrouping(SENTENCE_SPOUT_ID);

        //SplitSentenceBolt单词分割器设置4个Task,2个Executeor(线程)
        builder.setBolt(SPLIT_BOLT_ID, SplitBolt,2).setNumTasks(4).shuffleGrouping(SENTENCE_SPOUT_ID);

        // SplitSentenceBolt --> WordCountBolt

        //fieldsGrouping将含有特定数据的tuple路由到特殊的bolt实例中
        //这里fieldsGrouping()方法保证所有“word”字段相同的tuuple会被路由到同一个WordCountBolt实例中
        //WordCountBolt单词计数器设置4个Executeor(线程)
        builder.setBolt(COUNT_BOLT_ID, countBolt,4).fieldsGrouping( SPLIT_BOLT_ID, new Fields("word"));

        // WordCountBolt --> ReportBolt

        //globalGrouping是把WordCountBolt发射的所有tuple路由到唯一的ReportBolt
        builder.setBolt(REPORT_BOLT_ID, reportBolt).globalGrouping(COUNT_BOLT_ID);


        Config config = new Config();//Config类是一个HashMap<String,Object>的子类,用来配置topology运行时的行为
        //设置worker数量
        //config.setNumWorkers(2);
        LocalCluster cluster = new LocalCluster();

        //本地提交
        cluster.submitTopology(TOPOLOGY_NAME, config, builder.createTopology());

        Utils.sleep(10000);
        cluster.killTopology(TOPOLOGY_NAME);
        cluster.shutdown();

    }
}

注:本文演示的为storm本地运行模式,集群模式带后续文章。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值