storm实时计算框架(笔记)

storm认识:

      Storm是一个免费开源、分布式、高容错的实时计算系统。Storm令持续不断的流计算变得容易,弥补了Hadoop批处理所不能满足的实时要求。Storm经常用于在实时分析、在线机器学习、持续计算、分布式远程调用和ETL等领域。Storm的部署管理非常简单,而且,在同类的流式计算工具,Storm的性能也是非常出众的。

      Storm主要分为两种组件NimbusSupervisor。这两种组件都是快速失败的,没有状态。任务状态和心跳信息等都保存在Zookeeper上的,提交的代码资源都在本地机器的硬盘上。

Nimbus负责在集群里面发送代码,分配工作给机器,并且监控状态。全局只有一个。

Supervisor会监听分配给它那台机器的工作,根据需要启动/关闭工作进程Worker。每一个要运行Storm的机器上都要部署一个,并且,按照机器的配置设定上面分配的槽位数。

Zookeeper是Storm重点依赖的外部资源。Nimbus和Supervisor甚至实际运行的Worker都是把心跳保存在Zookeeper上的。Nimbus也是根据Zookeerper上的心跳和任务运行状况,进行调度和任务分配的。

Storm提交运行的程序称为Topology。

Topology处理的最小的消息单位是一个Tuple,也就是一个任意对象的数组。

topology是由Spout和Bolt构成。Spout是发出Tuple的结点。Bolt可以随意订阅某个Spout或者Bolt发出的Tuple。Spout和Bolt都统称为component

下图是一个Topology设计的逻辑图的例子。

图文解释:

水龙头:spout

闪电标识:blot

Topology的提交流程图:


下图是Storm的数据交互图。可以看出两个模块Nimbus和Supervisor之间没有直接交互。状态都是保存在Zookeeper上。Worker之间通过ZeroMQ传送数据。


工作流程:Storm 集群的输入流由一个被称作 spout 的组件管理,spout 把数据传递给 boltbolt 要么把数据保存到某种存储器,要么把数据传递给其它的 bolt。你可以想象一下,一个 Storm 集群就是在一连串的 bolt 之间转换 spout 传过来的数据。

storm的分组类型(6种):

1. Shuffle Grouping 

随机分组,随机派发stream里面的tuple,保证每个bolt task接收到的tuple数目大致相同。轮询,平均分配 。


2. Fields Grouping(相同fields去分发到同一个Bolt)

按字段分组,比如,按"user-id"这个字段来分组,那么具有同样"user-id"的 tuple 会被分到相同的Bolt里的一个task, 而不同的"user-id"则可能会被分配到不同的task。 


3. All Grouping

广播发送,对于每一个tuple,所有的bolts都会收到 


4. Global Grouping

全局分组,把tuple分配给task id最低的task 。


5. None Grouping

不分组,这个分组的意思是说stream不关心到底怎样分组。目前这种分组和Shuffle grouping是一样的效果。 有一点不同的是storm会把使用none grouping的这个bolt放到这个bolt的订阅者同一个线程里面去执行(未来Storm如果可能的话会这样设计)。 


6. Direct Grouping

指向型分组, 这是一种比较特别的分组方法,用这种分组意味着消息(tuple)的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为 Direct Stream 的消息流可以声明这种分组方法。而且这种消息tuple必须使用 emitDirect 方法来发射。消息处理者可以通过 TopologyContext 来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id) 

具体案例:

Spout(产生数据):

public class MySpout implements IRichSpout {

    private static final long serialVersionUID = 1L;

    FileInputStream fis;

    InputStreamReader isr;

    BufferedReader br;

    SpoutOutputCollector collector = null;

    String str = null;

    @Override

    public void nextTuple() {//真正发的逻辑

        try {

            while ((str = this.br.readLine()) != null) {

                // 过滤动作

                collector.emit(new Values(str, str.split("\t")[1]));//发出数据,一行和一行切分完后第二个字段。

            }

        } catch (Exception e) {

        }

    }

    @Override

    public void close() {//释放资源

        try {

            br.close();

            isr.close();

            fis.close();

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

    @Override

    public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {//初始化(方法只调用一次)

        try {

            this.collector = collector;

            this.fis = new FileInputStream("track.log");

            this.isr = new InputStreamReader(fis, "UTF-8");

            this.br = new BufferedReader(isr);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

    @Override

    public void declareOutputFields(OutputFieldsDeclarer declarer) {//声明发出去的字段

        declarer.declare(new Fields("log", "session_id"));

    }

    @Override

    public Map getComponentConfiguration() {

        return null;

    }

    @Override

    public void ack(Object msgId) {

        System.out.println("spout ack:" + msgId.toString());

    }

    @Override

    public void activate() {

    }

    @Override

    public void deactivate() {

    }

    @Override

    public void fail(Object msgId) {

        System.out.println("spout fail:" + msgId.toString());

    }

}

处理bolt单元:

public class MyBolt implements IRichBolt {

    private static final long serialVersionUID = 1L;

    OutputCollector collector = null;

    int num = 0;

    String valueString = null;

    @Override

    public void cleanup() {

    }

    @Override

    public void execute(Tuple input) {

        try {

            valueString = input.getStringByField("log");//通过fields接收数据

            if (valueString != null) {

                num++;

                System.err.println(input.getSourceStreamId() + " " + Thread.currentThread().getName() + "--id="//打印当前进程名字

                        + Thread.currentThread().getId() + "  lines  :" + num + "  session_id:"//打印当前进程id

                        + valueString.split("\t")[1]);//这行词的第二个字母

            }

            collector.ack(input);

            // Thread.sleep(2000);

        } catch (Exception e) {

            collector.fail(input);

            e.printStackTrace();

        }

    }

    @Override

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

        this.collector = collector;

    }

    @Override

    public void declareOutputFields(OutputFieldsDeclarer declarer) {

        declarer.declare(new Fields(""));//声明空即可

    }

    @Override

    public Map getComponentConfiguration() {

        return null;

    }

}

main方法:

public class Main {

    public static void main(String[] args) {

        TopologyBuilder builder = new TopologyBuilder();

        builder.setSpout("spout", new MySpout(), 1);//拓扑名,数据源,并行度

        builder.setBolt("bolt", new MyBolt(), 2).allGrouping("spout");//两个spot并行 所有都分发

        //builder.setBolt("bolt", new MyBolt(), 2).shuffleGrouping("spout");// shuffleGrouping其实就是随机往下游去发,不自觉的做到了负载均衡


        //builder.setBolt("bolt", new MyBolt(), 2).fieldsGrouping("spout", new Fields("session_id")); // fieldsGrouping其实就是MapReduce里面理解的Shuffle,根据fields求hash来取模

        //builder.setBolt("bolt", new MyBolt(), 2).globalGrouping("spout"); // 只往一个里面发,往taskId小的那个里面去发送

        // builder.setBolt("bolt", new MyBolt(), 2).noneGrouping("spout");  // 等于shuffleGrouping

        // Map conf = new HashMap();

        // conf.put(Config.TOPOLOGY_WORKERS, 4);

        Config conf = new Config();

        conf.setDebug(false);

        conf.setMessageTimeoutSecs(30);

        if (args.length > 0) {

            try {

                StormSubmitter.submitTopology(args[0], conf, builder.createTopology());//集群方式

            } catch (AlreadyAliveException e) {

                e.printStackTrace();

            } catch (InvalidTopologyException e) {

                e.printStackTrace();

            }

        } else {

            LocalCluster localCluster = new LocalCluster();

            localCluster.submitTopology("mytopology", conf, builder.createTopology());// 本地模拟参数分别为名称,配置,构建拓扑结构。

        }

    }

}

结果:

1. builder.setBolt("bolt", new MyBolt(), 2).allGrouping("spout");//两个spot并行 所有都分发

 2. builder.setBolt("bolt", new MyBolt(), 2).shuffleGrouping("spout")其实就是随机往下游去发,不自觉的做到了负载均衡

3.builder.setBolt("bolt", new MyBolt(), 2).fieldsGrouping("spout", new Fields("session_id")); // fieldsGrouping其实就是MapReduce里面理解的Shuffle,根据fields求hash来取模,相同的名称的fields分发到一个bolt里面。

4.builder.setBolt("bolt", new MyBolt(), 2).globalGrouping("spout"); // 只往一个里面发,往taskId小的那个里面去发送

转载博客:

https://www.cnblogs.com/langtianya/p/5199529.html

 https://www.cnblogs.com/LHWorldBlog/p/8352994.html

你可能感兴趣的:(storm实时计算框架(笔记))