storm流计算编程实现电话呼叫日志处理

storm是一个免费、开源、分布式、实时计算系统。吞吐量高。每秒每节点百万元组。

      storm                           VS                        hadoop
-----------------------------------------------------------
    实时流处理                                                  批处理
    无状态                                                         有状态
    使用zk协同的主从架构                                无zk的主从架构。  

    每秒处理数万消息                                       HDFS MR数分钟、数小时

    不会主动停止                                               终有完成的时候。

 

storm优点
-------------
    1.跨语言       2.可伸缩的     3.低延迟,秒级/分钟级     4.容错。

核心概念
--------------
    1.Tuple           主要的数据结构,有序元素的列表。
    2.Stream        Tuple的序列。
    3.Spouts         数据流源头。可以读取kafka队列消息。可以自定义。
    4.Bolts            转接头. 逻辑处理单元。spout的数据传递个bolt,bolt计算,完成后产生新的数据。IBolt是接口。


Topology  :           Spout + bolt连接在一起形成一个top,形成有向图,定点就是计算,边是数据流
task :    Bolt中每个Spout或者bolt都是一个task.

Storm架构
---------------------
    1.Nimbus(灵气)
        master节点。
        核心组件,运行top。
        分析top并收集运行task。分发task给supervisor.
        监控top。
        无状态,依靠zk监控top的运行状况。

    2.Supervisor(监察)
        每个supervisor有n个worker进程,负责代理task给worker。
        worker在孵化执行线程最终运行task。
        storm使用内部消息系统在nimbus和supervisor之间进行通信。

        接受nimbus指令,管理worker进程完成task派发。

    3.worker
        执行特定的task,worker本身不执行任务,而是孵化executors,
        让executors执行task。
    
    4.Executor
        本质上有worker进程孵化出来的一个线程而已。
        executor运行task都属于同一spout或者bolt.
    
    5.task
        执行实际上的任务处理。或者是Spout或者是bolt.

    
storm工作流程
----------------
    1.nimbus等待提交的top
    2.提交top后,nimbus收集task,
    3.nimbus分发task给所有可用的supervisor
    4.supervisor周期性发送心跳给nimbus表示自己还活着。
    5.如果supervisor挂掉,不会发送心跳给nimubs,nimbus将task发送给其他的supervisor
    6.nimubs挂掉,super会继续执行自己task。
    7.task完成后,supervisor等待新的task
    8.同时,挂掉的nimbus可以通过监控工具软件自动重启。

 

安装storm集群
------------------
    [datanode1 ~ datanode4]
    1.jdk
    2.tar
    3.环境变量
    4.验证安装
        $>source /etc/profile
        $>./storm version
    5.分发安装文件到其他节点。 
    
    6.配置
        [storm/conf/storm.yaml]
        storm.local.dir: "/soft/storm"
        storm.zookeeper.servers:
            - "datanode2"
            - "datanode3"

        storm.zookeeper.port: 2181

        ### nimbus.* configs are for the master
        nimbus.seeds : ["datanode1"]

        ### ui.* configs are for the master
        ui.host: 0.0.0.0
        ui.port: 8080

        supervisor.slots.ports:
            - 6700
            - 6701
            - 6702
            - 6703
    7.分发 到datanode2 ~ datanode4

    8.启动进程
        a)启动datanode1 nimbus进程
            $>storm nimbus &

        b)启动datanode2 ~ datanode4 supervisor进程
            $>storm supervisor &
 
        c)启动datanode1的ui进程
            $>storm ui &
    
    9.通过webui查看
        http://datanode1:8080/

 

编程实现CallLog日志统计:

pom.xml
      

 
        
            4.0.0

            com.jr
            StormDemo
            1.0-SNAPSHOT

            
                
                    org.apache.storm
                    storm-core
                    1.0.3
                
            
            
        

CallLogSpout :

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

		import java.util.ArrayList;
		import java.util.List;
		import java.util.Map;
		import java.util.Random;

		/**
		 * Spout类,负责产生数据流
		 */
		public class CallLogSpout implements IRichSpout{

			//Spout输出收集器
			private SpoutOutputCollector collector;

			//是否完成
			private boolean completed = false;

			//上下文
			private TopologyContext context;

			//随机发生器
			private Random randomGenerator = new Random();

			//
			private Integer idx = 0;

			public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
				this.context = context;
				this.collector = collector;
			}

			public void close() {
			}

			public void activate() {
			}

			public void deactivate() {

			}

			/**
			 * 下一个元组
			 */
			public void nextTuple() {
				if (this.idx <= 1000) {
					List mobileNumbers = new ArrayList();
					mobileNumbers.add("1234123401");
					mobileNumbers.add("1234123402");
					mobileNumbers.add("1234123403");
					mobileNumbers.add("1234123404");

					Integer localIdx = 0;
					while (localIdx++ < 100 && this.idx++ < 1000) {
						//取出主叫
						String caller = mobileNumbers.get(randomGenerator.nextInt(4));
						//取出被叫
						String callee = mobileNumbers.get(randomGenerator.nextInt(4));
						while (caller == callee) {
							//重新取出被叫
							callee = mobileNumbers.get(randomGenerator.nextInt(4));
						}
						//模拟通话时长
						Integer duration = randomGenerator.nextInt(60);

						//输出元组
						this.collector.emit(new Values(caller, callee, duration));
					}
				}
			}

			public void ack(Object msgId) {

			}

			public void fail(Object msgId) {

			}

			/**
			 * 定义输出的字段名称
			 */
			public void declareOutputFields(OutputFieldsDeclarer declarer) {
				declarer.declare(new Fields("from", "to", "duration"));
			}

			public Map getComponentConfiguration() {
				return null;
			}
		}

CreatorBolt:


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

		import java.util.Map;

		/**
		 * 创建CallLog日志的Bolt
		 */
		public class CallLogCreatorBolt implements IRichBolt {
			//
			private OutputCollector collector;

			public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
				this.collector = collector ;
			}

			public void execute(Tuple tuple) {
				//处理通话记录
				String from = tuple.getString(0);
				String to = tuple.getString(1);
				Integer duration = tuple.getInteger(2);
				//产生新的tuple
				collector.emit(new Values(from + " - " + to, duration));
			}

			public void cleanup() {

			}

			/**
			 * 设置输出字段的名称
			 */
			public void declareOutputFields(OutputFieldsDeclarer declarer) {
				declarer.declare(new Fields("call", "duration"));
			}

			public Map getComponentConfiguration() {
				return null;
			}
		}

创建CounterBolt

package com.it18zhang.stormdemo;

		import org.apache.storm.task.IBolt;
		import org.apache.storm.task.OutputCollector;
		import org.apache.storm.task.TopologyContext;
		import org.apache.storm.topology.IRichBolt;
		import org.apache.storm.topology.OutputFieldsDeclarer;
		import org.apache.storm.tuple.Fields;
		import org.apache.storm.tuple.Tuple;

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

		/**
		 * 通话记录计数器Bolt
		 */
		public class CallLogCounterBolt implements IRichBolt{

			Map counterMap;
			private OutputCollector collector;

			public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
				this.counterMap = new HashMap();
				this.collector = collector;
			}

			public void execute(Tuple tuple) {
				String call = tuple.getString(0);
				Integer duration = tuple.getInteger(1);

				if (!counterMap.containsKey(call)) {
					counterMap.put(call, 1);
				} else {
					Integer c = counterMap.get(call) + 1;
					counterMap.put(call, c);
				}
				collector.ack(tuple);
			}

			public void cleanup() {
				for (Map.Entry entry : counterMap.entrySet()) {
					System.out.println(entry.getKey() + " : " + entry.getValue());
				}
			}

			public void declareOutputFields(OutputFieldsDeclarer declarer) {
				declarer.declare(new Fields("call"));
			}

			public Map getComponentConfiguration() {
				return null;
			}
		}

4.App实现调用类

package com.it18zhang.stormdemo;

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

		/**
		 * App
		 */
		public class App {
			public static void main(String[] args) throws InterruptedException {
				TopologyBuilder builder = new TopologyBuilder();
				//设置Spout
				builder.setSpout("spout", new CallLogSpout());
				//设置creator-Bolt
				builder.setBolt("creator-bolt", new CallLogCreatorBolt()).shuffleGrouping("spout");
				//设置counter-Bolt
				builder.setBolt("counter-bolt", new CallLogCounterBolt()).fieldsGrouping("creator-bolt", new Fields("call"));

				Config conf = new Config();
				conf.setDebug(true);

				LocalCluster cluster = new LocalCluster();
				cluster.submitTopology("LogAnalyserStorm", conf, builder.createTopology());
				Thread.sleep(10000);

				//停止集群
				cluster.shutdown();
			}
		}

在IDEA运行即可看到程序运行结果

也可以打成jar包放到集群里边运行命令执行。

首先修改一下提交方式
            [App.java]
             public static void main(String[] args) throws Exception {
                    TopologyBuilder builder = new TopologyBuilder();
                    //设置Spout
                    builder.setSpout("spout", new CallLogSpout());
                    //设置creator-Bolt
                    builder.setBolt("creator-bolt", new CallLogCreatorBolt()).shuffleGrouping("spout");
                    //设置counter-Bolt
                    builder.setBolt("counter-bolt", new CallLogCounterBolt()).fieldsGrouping("creator-bolt", new Fields("call"));

                    Config conf = new Config();
                    conf.setDebug(true);

                    /**
                     * 本地模式storm
                     */
            //        LocalCluster cluster = new LocalCluster();
            //        cluster.submitTopology("LogAnalyserStorm", conf, builder.createTopology());
            //        Thread.sleep(10000);
                    StormSubmitter.submitTopology("mytop", conf, builder.createTopology());
                }
        b)导入jar包.
            maven projects->package 右键run stormdemo,然后就会在工程的target下有一个jar包生成,将jar放到服务器。
        
        c)在centos上运行top
            $>storm jar xxx.jar com.jr.stormdemo.App

你可能感兴趣的:(大数据)