Storm的简单分析

Storm的详细分析

Storm人的概述
  • Storm是Twitter开源的一个实时处理框架
  • Storm能够实现高频数据和大规模数据的实时处理
Storm与MapReduce的区别Storm
typeMapReduceStorm
数据来源hdfs上TB级别历史数据实时新增的某一条数据
处理过程map阶段和reduce阶段可以有很多阶段包含spout以及bolt
是否会结束执行完结束不会结束
处理速度主要以执行TB级别数据速度较慢只处理新增数据速度很快
适用场景处理批数据不讲时效性处理新增数据将时效性
Spark Streaming与Storm的区别
typeSpark StreamingStorm
计算模型是近实时处理框架全实时处理框架
延迟度最高支持秒级别的延迟可以支持毫秒级别的延迟
吞吐量因为是批处理所以吞吐量高吞吐量相对来说较低
动态调整并行度不支持支持
事务机制支持但是不够完善支持且完善
Storm各个组件解释
  • Topology:用于封装一个实时计算应用程序的逻辑
  • Stream:消息流,是一个没有边界的tuple序列,这些tuple会以分布式的方式进行创建以及处理
  • Spout:消息源,消息的生产者,会从外部源获取消息然后向Topology发出:tuple
  • Bolt:消息处理者,消息的处理逻辑被封装到bolt之中,处理输入的数据然后产生新的输出数据流
Storm的设计思想
  • 是对stream流的一个抽象即一个不间断的连续tuple
  • 将流中的元素抽象为一个tuple,一个tuple就是一个值列表value list,list中的每个value都有一个name,并且这个value可以是很多数据类型例如基本类型、字符类型等
  • 每一个stream流都有一个数据源,称为Spout
  • stream从spout中获取不间断数据tuple需要经过处理。处理的过程就是stream流转换的过程称为bolt,bolt可以消费任意数量的流,它是将stream汇总的tuple挨个实时进行处理转换成一个新的stream流经过多个bolt处理就可以得到目标数据
  • spout+tuple+bolt这个过程可以称为是Topology拓扑。Topology是Storm中最高的一个抽象概念他可以被提交到集群中执行
  • Topology的每个节点都要指定他所发射数据的name,其他节点只需要订阅该name就可以接收数据进行处理
Topology的整个流程
  • 如果将stream比作是一列火车的话 spout就是这列火车的始发站每一节车厢就是一个tuple乘客就是tuple中的values 中间的站点就相当于是bolt进行处理上下乘客终点站就相当于stream的目标数据

在这里插入图片描述

Storm的整体架构图

在这里插入图片描述

Storm的简单实例开发
  • 需求:一个源源不断的数据1,2,3,4…求每出现一个数字就要计算出现的所有数字的和

  • 开发过程

    • 在IDE中创建maven工程

    • 在pom中添加、Storm依赖

      <dependency>
          <groupId>org.apache.storm</groupId>
          <artifactId>storm-core</artifactId>
          <version>1.0.6</version>
          <scope>provided</scope>
      </dependency>
      
    • package Storme;
      
      import java.util.Map;
      
      import org.apache.storm.Config;
      import org.apache.storm.LocalCluster;
      import org.apache.storm.generated.StormTopology;
      import org.apache.storm.spout.SpoutOutputCollector;
      import org.apache.storm.task.OutputCollector;
      import org.apache.storm.task.TopologyContext;
      import org.apache.storm.topology.OutputFieldsDeclarer;
      import org.apache.storm.topology.TopologyBuilder;
      import org.apache.storm.topology.base.BaseRichBolt;
      import org.apache.storm.topology.base.BaseRichSpout;
      import org.apache.storm.tuple.Fields;
      import org.apache.storm.tuple.Tuple;
      import org.apache.storm.tuple.Values;
      import org.apache.storm.utils.Utils;
      
      /**
       * 	需求:实现数字累加求和
       * 	分析:
       * 	需要有一个spout负责源源不断的产生从1开始的递增数字
       * 	还需要有一个bolt负责对spout产生的数据进行累加求和,并且把结果打印到控制台
       * 	最后把这个spout和bolt组装成一个topology
       *
       */
      public class WordCount {
      	/**
      	 * 	实现自己的数据源spout,
      	 * 	该spout负责源源不断产生从1开始的递增数字
      	 *
      	 */
      	public static class MySpout extends BaseRichSpout{
      		
      		private Map conf;//这里面存储配置信息
      		private TopologyContext context;//代表上下文
      		private SpoutOutputCollector collector;//收集器,主要负责向外面发射数据
      		
      		/**
      		 * 	是一个初始化的方法,这个方法在本实例运行的之后,首先被调用,仅且仅被调用一次
      		 * 	所以这个方法内一般放一些初始化的代码
      		 * 	例子:针对操作mysql数据的案例,使用jdbc获取数据库连接的代码需要放到这里面实现
      		 */
      		public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
      			this.conf = conf;
      			this.context = context;
      			this.collector = collector;
      			//System.err.println("spout------"+conf.get("name"));
      		}
      		/**
      		 * 	这个方法会被循环调用
      		 */
      		int i = 1;
      		public void nextTuple() {
      			//	注意:针对需要发射的数据,需要封装成tuple,可以使用storm中的values对象快速封装tuple
      			System.out.println("spout:"+i);
      			this.collector.emit(new Values(i++));
      			//	让线程每发射一条数据,休息1秒
      			Utils.sleep(1000);
      		}
      		/**
      		 * 	声明输出字段
      		 * 	定义两个组件之间数据传输的一个规则
      		 * 	注意:只要这个组件(spout/spout)向外发射了数据,那么这个declareOutputFields就需要实现
      		 */
      		public void declareOutputFields(OutputFieldsDeclarer declarer) {
      			//	注意:Fields中的字段列表和Values中的数据列表是一一对应的
      			declarer.declare(new Fields("num"));
      		}
      	}
      	/**
      	 * 	聚合的Bolt,负责把Spout发射出来的数据进行累加求和,并且打印到控制台
      	 *
      	 */
      	public static class SumBolt extends BaseRichBolt{
      		private Map stormConf;
      		private TopologyContext context; 
      		private OutputCollector collector;
      		/**
      		 * prepare是一个初始化方法,只会执行一次,这里面也是可以放一些初始化的代码
      		 */
      		public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
      			this.stormConf = stormConf;
      			this.context = context;
      			this.collector = collector;
      			//System.err.println("bolt------"+stormConf.get("name"));
      		}
      		int sum = 0;
      		/**
      		 * 	这个方法也是会被循环调用
      		 * 	主要上一个组件向外发射了数据,那么这个方法就会被调用一次
      		 */
      		public void execute(Tuple input) {
      			//input.getInteger(0);//	通过角标获取数据
      			Integer num = input.getIntegerByField("num");
      			sum += num;
      			System.out.println("和为:"+sum);
      		}
      		/**
      		 * 	注意:这个方法在这里就不需要实现了,因为这个bolt没有向下一个组件发射数据
      		 */
      		public void declareOutputFields(OutputFieldsDeclarer declarer) {
      		}
      	}
      	public static void main(String[] args) {
      		TopologyBuilder builder = new TopologyBuilder();
      		//	组装spout
      		builder.setSpout("spoutid", new MySpout());
      		//	组装bolt,并且告诉bolt接收哪个组件的数据
      		builder.setBolt("bolt-1", new SumBolt()).shuffleGrouping("spoutid");
      		StormTopology createTopology = builder.createTopology();
      		//	通过代码创建一个本地集群
      		LocalCluster localCluster = new LocalCluster();
      		String topologyName = WordCount.class.getSimpleName();
      		Config config = new Config();
      		config.put("name", "zs");
      		//	把代码提交到本地集群中运行
      		localCluster.submitTopology(topologyName, config, createTopology);
      	}
      }
      
      
      
Storm核心之并行度
组件解释
  • worker:worker是一个进程,每一个worker进程里面都执行的是一个Topology的任务(不会出现一个worker执行多个Topology的任务)。一个worker中会启动一个或多个executor线程来执行Topology的spout或者bolt组件。一个Topology会使用一个或者多个worker来执行任务
  • executor:是worker进程内部启动的独立线程,每一个executor会产生一个或者多个task(storm默认是一个task即一个spout或者bolt有一个task,如果有多个task,executor会循环调用所有task中的实例)
  • task:是最终运行spout或者bolt中具体代码的执行单元。Topology启动(spout或者bolt)的task的数目是不变的,但是executor线程的数量可以动态进行调整(例如:1个executor线程可以执行该(spout或bolt)的1个或多个task实例)。这意味着,对于1个(spout或bolt)存在这样的条件:#threads<=#tasks(即:线程数小于等于task数目)。默认情况下task的数目等于executor线程数目,即1个executor线程只运行1个task。
  • 默认情况下,一个supervisor节点最多可以启动4个worker进程,每一个topology默认占用一个worker进程,每个spout或者bolt会占用1个executor,每个executor启动1个task。

[外链图片转存失败(img-1yj8eyka-1566215726662)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1566213893905.png)]

提高Storm组件的并行度
  • worker(slot)【间接】
    • 默认一个节点最多可以启动四个worker进程,可以修改进程数量strom-core.jar/defaults.yaml/supervisor.slots.ports
    • 默认一个Topology只有一个worker进程,可以通过代码指定一个Topology使用多个worker进程config.setNumWorkers(workersnum)
    • 注意:如果worker使用完在提交Topology就不会执行,会处于等待状态。worker之是通过Netty通信的
  • executor【直接】
    • 默认情况下一个executor只会运行一个task,可以直接通过代码修改增加task数量,会直接提高Storm组件的并行度
    • builder.setSpout(id, spout,parallelism_hint);
    • builder.setBolt(id, bolt,parallelism_hint);
  • task【间接】
    • 通过boltDeclarer.setNumTasks(num);来设置实例的个数
    • executor的数量会小于等于task的数量(为了rebalance)
      在这里插入图片描述
弹性计算rebalance
  • 前提是Topology中的task数量要大于executor线程数
  • 通过shell调整
    • storm rebalance mytopology -w 10 -n 5 -e blue-spout=3 -e yellow-bolt=10
    • 注意:acker的树木运行时是不会变化的,所以多指定几个worker进程,acker的数量也不会增加
    • -w:表示超时时间,Rebalance会在一个超时时间内注销掉Topology,然后在集群中重新分配worker
    • -n:表示的是worker的数量
    • -e:调整组件的并行度
    • 注:-n 以及 -e 都可以单独使用或者组合起来使用
  • 通过UI界面进行调整,不建议使用所以就不具体解释使用方法了
并行度设置多少合适
  • 单spout每秒大概可以发送500个tuple
  • 单bolt每秒大概可以接收2000个tuple
  • 单acker每秒大概可以接收6000个tuple
  • 根据需要进行调整
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值