Storm学习

一、Storm介绍

在这里插入图片描述
官方网址:http://storm.apache.org/
官方对于Storm的介绍:
  Apache Storm is a free and open source distributed realtime computation system. Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing what Hadoop did for batch processing.
  Storm has many use cases: realtime analytics, online machine learning, continuous computation, distributed RPC, ETL, and more.
  Storm is fast: a benchmark clocked it at over a million tuples processed per second per node. It is scalable, fault-tolerant, guarantees your data will be processed, and is easy to set up and operate.
Storm是一个分布式的实时计算框架,具有可扩展,容错等特性。可以应用于实时计算,在线机器学习等领域。

二、Storm的应用场景

·   对海量数据进行批处理运算,Hadoop依旧保持着无法撼动的地位。但在对实时性要求较高的应用场景中,Hadoop需要将数据先落地存储到HDFS上,然后再通过MapReduce进行计算。这样的批处理运算流程使它很难将延时缩小到秒级。
Storm的处理速度最快可以达到毫秒级别。Storm的QPS (Query Per Second)达到9万~10万。
·  Storm的另外一个优势在于:Storm可以一个一个tuple处理,(细粒度处理),所以像金融领域的实时流处理,优先选择Storm。
·  Storm是基于数据流的实时处理系统,提供了大吞吐量的实时计算能力(因为Storm是一个分布式架构)。每条数据到达系统时,立即在内存中进入处理流程,并在很短的时间内处理完成。实时性要求较高的数据分析场景,都可以尝试使用Storm作为技术解决方案。

应用场景

·  语音实时墙 、网络流量流向实时分析、交通—基于GPS的实时路况分析等

三、Storm架构原理

1.设计思想
  在Storm中有对流(Stream)的抽象,Stream流是一个不间断的、无界的连续Tuple。Tuple是包含一个或多个键值对的集合。
(1)Spout
  Storm认为每个流都有一个Stream源,也就是原始元组的源头,所以它将这个源头抽象为Spout(水龙头),Spout可以通过API生成数据装配为Tuple发送,也可能从某个队列中不断读取队列元素并装配为Tuple发射。所以,spout用来产生数据
(2)Bolt
  Storm将流的中间状态转换抽象为Bolt(水槽),Bolt可以消费任意数量的输入流,只要将流方向导向该Bolt,同时它也可以发送新的流给其他Bolt使用或者目的地。所以,bolt用来处理数据
  假设Spout就是一个一个的水龙头,并且每个水龙头里流出的水是不同的,想获得哪种水就拧开哪个水龙头,然后使用管道将水龙头的水导向到一个水处理器(Bolt),水处理器处理后使用管道导向另一个处理器或者存入容器中。如下图所以Spout、Tuple和Bolt之间的关系和流程。

在这里插入图片描述

`  Storm整个的流程图可以看做是一个有向无环图,更抽象的来说,是一个拓扑图为Topology(即拓扑),拓扑是Storm中最高层次的一个抽象概念,提交拓扑到Storm集群执行。
(3)Topology(拓扑)的概念
  Storm分布式计算结构称为topology(拓扑),由stream(数据流),spout(数据源的生成者),bolt(运算)组成。Storm topology大致等同与Hadoop这类批处理运算中的job。不过,批处理运算中的job对运算的起始和终止有着明确定义,而Storm topology会一直运行下去,除非进程被杀死或被取消部署。
  1)Stream
  Stream是由无限制连续的tuple组成的序列,tuple是Storm最核心的数据结构。
  2)spout
  spout代表了一个Storm topology的主要数据入口,充当采集器的角色,连接到数据源,将数据转化为一个个tuple,并将tuple作为数据流进行发射。
  开发一个spout的主要工作就是编写代码从数据源或者API消费数据。
  数据源可能包括以下几种:Web或者移动程序的点击流、Twitter或其他社交网络的消息、传感器的输出、应用程序的日志事件
  3)bolt
  bolt可以理解为计算程序中的运算或者函数,将一个或者多个数据流作为输入,对数据实施运算后,选择性地输出一个或者多个数据流。bolt可以订阅多个由spout或者其他bolt发射的数据流,这样就可以建立复杂的数据流转换网络。
  
案例-单词统计

实现步骤:
 1.创建普通java工程
 2.将Storm依赖包导入
 3.编写各组件代码

WordCountSpout代码:

public class WordCountSpout extends BaseRichSpout{
 
private String[] data=new String[]{
"hello storm",
"hello world"     
};
 
private SpoutOutputCollector collector;
 
private static int i=0;
 
@Override
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector=collector;
}
 
@Override
public void nextTuple() {
Values line=new Values(data[i]);
collector.emit(line);
if(i==data.length-1){
i=0;
}else{
i++;
}
}
 
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("line"));
 
}
}

SplitBolt代码:

 public class SplitBolt extends BaseRichBolt{
 
private OutputCollector collector;
 
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector=collector;
}
 
@Override
public void execute(Tuple input) {
String line=input.getStringByField("line");
 
String[] words=line.split(" ");
for(String word:words){
collector.emit(new Values(word));        
}
}
 
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word")); 
}
}

WordCountBolt代码:

public class WordCountBolt extends BaseRichBolt{
 
private OutputCollector collector;
 
private Map<String,Integer> map=new HashMap<>();
 
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector=collector; 
}
 
@Override
public void execute(Tuple input) {
String word=input.getStringByField("word");
 if(map.containsKey(word)){
map.put(word, map.get(word)+1);
}else{
map.put(word, 1);
}
 
collector.emit(new Values(word,map.get(word)));
 
}
 
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word","count"));
 
}
}

ReportBolt代码:

public class ReportBolt extends BaseRichBolt{
 
private OutputCollector collector;
 
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector=collector; 
}
 
@Override
public void execute(Tuple input) {
String word=input.getStringByField("word");
int count=input.getIntegerByField("count");
System.out.println("单词:"+word+"当前的频率为=+"+count);
}
 
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) { 
}
}

WordCountTopology代码:

public class WordCountTopology {
 
public static void main(String[] args) {
Config config=new Config();
LocalCluster cluster=new LocalCluster();
 
TopologyBuilder builder=new TopologyBuilder();
WordCountSpout spout=new WordCountSpout();
SplitBolt splitBolt=new SplitBolt();
WordCountBolt wordcountBolt=new WordCountBolt();
ReportBolt reportBolt=new ReportBolt();
 
builder.setSpout("wordcount_spout", spout);
builder.setBolt("split_bolt", splitBolt).shuffleGrouping("wordcount_spout");
builder.setBolt("wordcount_bolt", wordcountBolt).fieldsGrouping("split_bolt",new Fields("word"));
builder.setBolt("report_bolt", reportBolt).globalGrouping("wordcount_bolt");
 
StormTopology topology=builder.createTopology();
 
cluster.submitTopology("wordcount_topology",config,topology);
 
}
}

四、Storm数据流分组

  1. 概述
    我们来考虑这样一种情况:
    当一个做单词统计的topology的并发如上图时,我们需要考虑什么问题?
    在这里插入图片描述
    1)WordCountSpout——>SplitBolt,发送的数据是 一行一行的数据,任何一个SplitBolt都可以进行处
    2)SplitBolt——>WordcountBolt,发送的数据是 一个一个的单词,但这里就需要注意了,因为WordcountBolt要根据单词进行词频统计,所以,这里有个原则是,同一个单词,必须发给同一个WordcountBolt才行。
    3)WordcountBolt——>ReportBolt,发送的数据是 {单词,频次},reportBolt收到数据后打印即可

Stream消息流
  消息流是Storm中最关键的抽象,是一个没有边界的Tuple序列,这些Tuple以分布式的方式并行地创建和处理。定义消息流主要是定义消息流中的Tuple。每个消息流在定义时都会分配一个ID,因为单向消息流很普遍,OutputFieldsDeclarer定义了一些方法可以定义一个流而不用指定其ID。在这种情况下,该流有一个默认的ID。

Stream Grouping消息流组
  Stream Grouping(消息流组)就是用来定义一个流如何分配Tuple到Bolt。Storm包括5种数据流分组类型:
  1)随机分组(Shuffle Grouping):
  随机分发元组到Bolt,并保证每个Bolt获得相等数量的元组。
  2)字段分组*(Fields Grouping)*:
  根据指定字段分割数据流并分组。例如,根据“user-id”字段,具有该字段的Tuple被分到相同的Bolt,不同的“user-id”值则会被分配到不同的Bolt。底层是通过指定字段的hash值对Bolt数量取余来实现的。
  3)全复制分组(All Grouping):
  对于每一个Tuple来说,所有的Bolt都会收到,所有的Tuple被复制到Bolt的所有任务上,小心使用该分组。
  4)全局分组(Global Grouping)
  全部的流都分配到唯一的一个Bolt上,就是分配给ID最小的Task。
 注:
  这种模型是,对应的Bolt所设定的并发度没有意义,因为最后只有一个Bolt在进行处理。
  5)不分组(None Grouping):不分组的含义是,流不关心到底谁会收到它的Tuple。目前无分组等效于随机分组。一般不用这种方式。

五、Storm并发机制

1. 概述
  Storm集群中的并发度主要由以下四个概念来决定:
  1)Nodes–服务器—指的是Storm集群中的服务器,一个Storm集群中包含一个或者多个Node。
  2)Workers–JVM进程数–默认情况一个topology在一个进程中运行
—指一个Node上相互独立运作的JVM进程,每个Node可以配置运行一个或多个worker。
  3)Executor–执行线程数–默认情况每一个组件对象用一个线程来执行—指一个worker的jvm中运行的java线程。此外,多个task也可以指派给同一个executer来执行,但需要明确指定。
  4)Task–bolt或spout的实例对象–任务数–task需要在executors线程里执行。

2.Strom的并发度
  Storm的默认并发设置值是1。
  即:一台服务器(node)——为topology分配一个worker——每个executor执行一个task。
  在单机模式下增加并发的方式可以体现在分配更多的worker和executer给topology.
注:
  单机模式下,增加worker的数量不会有任何提升速度的效果。

Storm在执行任务时,底层分配策略
  尽可能满足负载均衡,每个进程所处理的线程数大致相同;
  Storm的并发机制的目的是提高拓扑的运行效率,即用分布式的思想处理拓扑任务。
  并发度的设置是Storm很重要的调优点。
  
如果通过代码增加Strom的并发度
  1)增加worker
  可以通过API和修改配置两种方式修改分配给topology的woker数量。
  2)增加Executor
  3)增加Task
在这里插入图片描述

builder.setSpout("wordCount_spout", spout,1).setNumTasks(1);
builder.setBolt("split_bolt", splitBolt,2).setNumTasks(4).shuffleGrouping("wordCount_spout");
builder.setBolt("wordCount_bolt", wordCountBolt,2).fieldsGrouping("split_bolt",new Fields("word"));
builder.setBolt("print_bolt", printBolt).globalGrouping("wordCount_bolt");

六、Strom集群中各角色说明

1.概述
  每一个工作节点上运行的Supervisor监听分配给它那台机器的工作,根据需要启动/关闭工作进程,每一个工作进程执行一个Topology的一个子集;一个运行的Topology由运行在很多机器上的很多工作进程Worker组成。那么Storm的核心就是主节点(Nimbus)、工作节点(Supervisor)、协调器(ZooKeeper)、工作进程(Worker)、任务线程(Task)。

2.主节点Nimbus
  主节点通常运行一个后台程序——Nimbus。
  Nimbus守护进程的主要职责是管理,协调和监控在集群上运行的topology。包括topology的发布,任务指派,事件处理失败时重新指派任务。一般任务起始,nimbus会初始化集群资源环境,获取每台supervisor可用的slot(槽位),slot用于启动worker进程。
  nimbus记录所有supervisor节点的状态和分配给它们的task。如果nimbus发现某个supervisor没有上报心跳或者已经不可达了,它会将故障supervisor分配的task重新分配到集群中的其他supervisor节点。
  nimbus不会引起单点故障。因为nimubs并不参与topology的数据处理过程,它仅仅是管理topology的初始化,任务分发和进行监控。如果nimbus守护进程在topology运行时停止了,只要分配的supervisor和worker正常运行,topology一直继续数据处理。此时你只需要重启nimbus进程即可,无任何影响。
  
但要注意的是:
  在nimbus已经停止的情况下supervisor异常终止,因为没有nimbus守护进程来重新指派失败这个终止的supervisor的任务,数据处理就会失败。不过这种概率是很小的,因为nimbus进程一般不会宕掉。
  目前storm官方出于nimbus宕机对集群影响不大的考虑,并没有实现nimbus的高可用方案。一般的处理办法:发现nimbus进程宕机,及时启动即可。
如果你想宕掉nimbus进程,使用kill -9即可。

3.工作节点Supervisor
  工作节点同样会运行一个后台程序——Supervisor,用于收听工作指派并基于要求运行工作进程。而Nimbus和Supervisor之间的协调则通过ZooKeeper系统。
  可以用kill-9来杀死Supervisor进程,然后重启就可以继续工作。

4.协调服务组件ZooKeeper
  ZooKeeper是完成Nimbus和Supervisor之间协调的服务。Storm使用ZooKeeper协调集群,由于ZooKeeper并不用于消息传递,所以Storm给ZooKeeper带来的压力相当低。Nimbus、Supervisor与ZooKeeper的关系如图所示。
在这里插入图片描述

5.Worker
  具体处理事务进程Worker:运行具体处理组件逻辑的进程。
6.Task
  具体处理线程Task:Worker中的每一个Spout/Bolt线程称为一个Task。在Storm 0.8之后,Task不再与物理线程对应,同一个Spout/Bolt的Task可能会共享一个物理线程,该线程称为Executor。

七、Storm任务分配调度流程及调优

Storm的任务分配流程及算法
  1、先由nimbus来计算拓扑的工作量,及计算多少个task,task的数目是指spout和bolt的并发度的分别的总和,例如一个拓扑中有一个spout和一个bolt,并且spout的task并发度为2,bolt的task并发度为3,则task数为5;
  2、nimbus会把计算好的工作分配给supervisor去做,工作分配的单位是task,即把计算好的一堆task分配给supervisor去做,即将task-id映射到supervisor-id+port上去,具体流程如下:
   ①从zk上获得已有的assignment任务
   ②查找所有可用的slot,所谓slot就是可用的worker,在所有supervisor上配置的多个worker的端口。
   ③将任务均匀地分配给可用的worker
  3、Supervisor会根据nimbus分配给他的任务信息来让自己的worker做具体的工作
  4、Worker会到zookeeper上去查找给他分配了哪些task,并且根据这些task-id来找到相应的spout/bolt,它还需要计算出这些spout/bolt会给哪些task发送消息,然后建立与这些task的连接,然后在需要发消息的时候就可以给相应的task发消息。

Nimbus的任务分配算法特点如下:
  1、在slot(槽位)充沛的情况下,能够保证所有topology的task被均匀的分配到整个集群的所有机器上
  2、在slot不足的情况下,它会把topology的所有的task分配到仅有的slot上去,这时候其实不是理想状态,所以在nimbus发现有多余slot的时候,它会重新分配topology的task分配到空余的slot上去以达到理想状态。
  3、 在没有slot的时候,它什么也不做

Storm与任务分配相关的配置选项:
  Storm自身的分配机制会尽量保证一个Topology会被平均分配到当前集群上,但是它没有考虑整个集群的负载均衡;例如现在集群有三台机器(三台Supervisor),每个上面的可用Slot数目均为四个,那么现在提交Topology,并且Topology占用1个worker,提交多个Topology后,它会先将整个集群中的一个机器占满,然后再去给别的机器分配。这种分配方式对有些场景是不太适用的,因此Storm自身的分配机制增加了额外的一个配置;

配置项如下:

default.schedule.mode: "average"

如果default.schedule.mode配置为average,则在使用默认的分配机制时会优先将任务分配给空闲Slot数目最多的机器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值