storm学习入门之概念、安装、简易使用(一)

16 篇文章 0 订阅
1 篇文章 0 订阅

标签(空格分隔): hadoop


重点内容

storm的核心组件
…编程模型
…task 并发度

storm是什么

storm是一个流式计算框架,神马是流式计算呢,就是针对于离线计算数据的延时性的补充,人家快啊,这样就既可以有实时的数据,也有历史的(mapreduce,spark)统计数据,两手抓嘛,心里才能安稳不是。

核心组件

我们还是按图索骥,先上一下我们滴下面这个图欣赏一下(欣赏不来没关系您可以画个更美的我回头贴上)。
storm角色介绍图.png-19.4kB
storm角色及流程图
以上是storm的相关组件及编程模型的角色,我们从上到下来look一下都是神马。
nimbus:可以理解为任务管理员,通过zk完成资源分配和任务的分配。(这年头都是可以ha滴)
supervisor:这个是进程管理器,就是管理本机上的进程,在这里就是管理work用滴。
worker: worker process 就是工作进程,这个工作进程里面主要包含了几个角色,spout,bolt这个主要是编程时用到的类。回头我们在编程里面会介绍下这些角色类之间的关系。

编程模型角色

storm编程角色概念图.png-24.9kB
编程角色图
1.Topology: 其实就是应用程序的名称啦。
2.spout:Topology提交后,spout组件会从外部数据源获取数据,并定义stream名称,以tuple元祖作为数据传输单元,往下面的组件传输数据就是bolt了。
3.bolt:这里只是稍微画了下,bolt不是一种可以有bolt1和bolt2 1至多种,bolt2如果依赖bolt1,bolt1会流转数据到bolt2.(ps:bolt和spot还有worker process的使用量,在编程时是可以指定的)
4.并发任务:这个图里面可以看到一个机器上可以有多个worker process(进程)。每个进程可以有多个excutor(线程),每个线程可以有1个spout or 一个bolt 或者1到多个的spout和bolt组成,其中每个组件其实都是一个任务,spout呢就是spout任务,bolt就是bolt任务,所以 spout+bolt任务=任务总数>=excutor任务数量。
5.groupsteam:就是流转策略 举几个例子

Storm里面有7种类型的stream grouping
	Shuffle Grouping: 随机分组, 随机派发stream里面的tuple,保证每个bolt接收到的tuple数目大致相同。
	Fields Grouping:按字段分组,比如按userid来分组,具有同样userid的tuple会被分到相同的Bolts里的一个task,而不同的userid则会被分配到不同的bolts里的task。
	All Grouping:广播发送,对于每一个tuple,所有的bolts都会收到。
	Global Grouping:全局分组, 这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。
	Non Grouping:不分组,这stream grouping个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果, 有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。
	Direct Grouping: 直接分组, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit方法也会返回task的id)。
	Local or shuffle grouping:如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。否则,和普通的Shuffle Grouping行为一致。

安装

安装大体可以有如下几个步骤:其实所有的安装都一个套路,下载二进制压缩包,解压,配置,分发,启动集群。
所以我们也就可以这样去官网下载 官网下载链接
storm安装指导文档
如果是2.0.0的有如下依赖

Java 8+ (Apache Storm 2.x is tested through travis ci against a java 8 JDK)
Python 2.6.6 (Python 3.x should work too, but is not tested as part of our CI enviornment) 说python3版本应该也可以运行但是不做保证。

之后按上方说的,先下载,在解压到某个地方,
上传到机器

cd /home/hadoop/apps/
tar -zxvf apache-storm-[version].tar.gz
ln -s apache-storm-2.0.0 storm
cd /storm/conf
vi storm.yaml #storm文件是yaml格式 

说明以下storm本身有一些配置是默认的默认配置说明storm默认配合项,如下的这几项配置是需要强制配置的

storm.zookeeper.servers:
  - "111.222.333.444"
  - "555.666.777.888"
storm.local.dir: "/mnt/storm" #这个配置项用来存储storm运行需要存放的状态数据,包括配置啊 提交的jar包啊,序列化文件啊啥的。 其实有有默认配置di
nimbus.seeds: ["111.222.333.44"] #nimbus候选机器
supervisor.slots.ports:   ## worker 一个端口一个worker看你自己怎么配置
- 6700
- 6701
- 6702
- 6703

我们继续做下配置关于storm.yaml的简化配置

#指定storm使用的zk集群
storm.zookeeper.servers:
     - "hadoop2"
     - "hadoop3"
     - "hadoop4"
#指定storm集群中的nimbus节点所在的服务器
nimbus.seeds: ["hadoop1", "hadoop2"]
#指定nimbus启动JVM最大可用内存大小
nimbus.childopts: "-Xmx1024m"
#指定supervisor启动JVM最大可用内存大小
supervisor.childopts: "-Xmx1024m"
#指定supervisor节点上,每个worker启动JVM最大可用内存大小
worker.childopts: "-Xmx768m"
#指定ui启动JVM最大可用内存大小,ui服务一般与nimbus同在一个节点上。
ui.childopts: "-Xmx768m"
#指定supervisor节点上,启动worker时对应的端口号,每个端口对应槽,每个槽位对应一个worker
supervisor.slots.ports:
    - 6700
    - 6701
    - 6702
    - 6703

将上方的配置复制进storm.yaml(注意留好空格)

#接下来就是分发了
cd /home/hadoop/apps/
scp -r apache-storm-..version hadoop2:$PWD
scp -r apache-storm-..version hadoop3:$PWD
scp -r apache-storm-..version hadoop4:$PWD
# 启动 由于我们配置了nimbus是两台我们在hadoop1和hadoop2启动nimbus hadoop2,3,4启动supervisor
nohup bin/storm nimbus & #后台启 hadoop1,2
nohup bin/storm ui & #默认端口8080 hadoop1
nohup bin/storm supervisor &    # hadoop2,hadoop3,hadoop3

使用

与mr一样,storm也有也谢提交包括一些其他常用的命令。下面我们来介绍下这些个命令,然后再写一个入门hello world。这样就慢慢熟悉了,后面找一个小项目来个项目代码。

命令行介绍

#提交任务
storm jar 【jar路径】 【拓扑包名.拓扑类名】 【拓扑名称】
#杀死任务
storm kill topology-name -w 10  # -w等待时长
# 任务的停用,重新启用等操作
storm deactivate topology-name # 挂起任务
#我们能够挂起或停用运行中的拓扑。当停用拓扑时,所有已分发的元组都会得到处理,但是spouts的nextTuple方法不会被调用。销毁一个拓扑,可以使用kill命令。它会以一种安全的方式销毁一个拓扑,首先停用拓扑,在等待拓扑消息的时间段内允许拓扑完成当前的数据流。
启用任务命令格式:storm activate【拓扑名称】 重新激活
storm activate topology-name
重新部署任务命令格式:storm rebalance  【拓扑名称】
storm rebalance topology-name
再平衡使你重分配集群任务。这是个很强大的命令。比如,你向一个运行中的集群增加了节点。再平衡命令将会停用拓扑,然后在相应超时时间之后重分配工人,并重启拓扑。就是重新分配节点

另外日志子在storm的logs目录下,可以查看相应的日志信息。

用storm写一个wordcount

其实storm的编程模型跟mapreduce真的很像。
新建一个stormops的maven项目:
pom:

    <dependency>
        <groupId>org.apache.storm</groupId>
        <artifactId>storm-client</artifactId>
        <version>2.0.0</version>
        <!--<scope>provided</scope>-->
    </dependency>
    <!--本地模式需要这个包-->
    <dependency>
        <groupId>org.apache.storm</groupId>
        <artifactId>storm-core</artifactId>
        <version>2.0.0</version>
        <!--<scope>provided</scope>-->
    </dependency>

类结构如下
image_1dgf1iqir14spuic1gtg17dj1qm09.png-23.5kB
入口类

package com.lcy.storm.mapreduce;

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

/**
 * Created by: luo
 * date: 2019/7/23.
 * desc:topology的入口
 */
public class MapReduceTopologyMain {

public static void main(String[] args) throws Exception {
    TopologyBuilder builder = new TopologyBuilder();
    builder.setSpout("words", new MyWordSpout(), 2);
    builder.setBolt("splict", new MysplictBolt(), 4)
            .shuffleGrouping("words");
    builder.setBolt("wordc", new WordCountBolt(), 4)
            .fieldsGrouping("splict",new Fields("word"));//根据哪个字段去执行这个分组策略
    StormTopology topology = builder.createTopology();
    Config config =  new Config();
    config.setNumWorkers(2);
    //本地模式,还有一个本地的drpc模式
//  LocalCluster localCluster = new LocalCluster();
// localCluster.submitTopology("mywordcount",config,topology);
    //storm的集群模式
    StormSubmitter.submitTopology(args[0],config,topology);
}
}

spout类:(map类通过指定地址获取数据,这里需要spout去获取数据)

package com.lcy.storm.mapreduce;

import org.apache.storm.lambda.SerializableSupplier;
import org.apache.storm.spout.ISpoutOutputCollector;
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.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;

import java.util.Map;

/**
 * Created by: luo
 * date: 2019/7/23.
 * desc:spout组件 用来获取外部数据源的
 */
public class MyWordSpout extends BaseRichSpout {
    //挺眼熟 这个是输出组件
    SpoutOutputCollector collector;
    @Override
    public void open(Map<String, Object> map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
        this.collector = spoutOutputCollector;
    }

    @Override
    public void nextTuple() {
        collector.emit(new Values("you will get me every time."));
        //这个是获取tuple的方法 每一次都发射这个数据,当然你也可以用其他的方法发送不同的数据
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        //用于做字段声明的,对应values 上面的字段,这个也是list
        outputFieldsDeclarer.declare(new Fields("allword"));
    }
}

splictbolt类:(获取数据之后我们做处理这个可以类比map)

package com.lcy.storm.mapreduce;

import org.apache.storm.lambda.SerializableBiConsumer;
import org.apache.storm.lambda.SerializableConsumer;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IBasicBolt;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.IWindowedBolt;
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;

/**
 * Created by: luo
 * date: 2019/7/23.
 * desc:第一个bolt,也是需要继承bolt基础类滴,否则需要一堆接口需要实现
 */
public class MysplictBolt extends BaseRichBolt {
    private OutputCollector collector;
    @Override
    public void prepare(Map<String, Object> topoConf, TopologyContext context, OutputCollector collector) {
        this.collector = collector;
    }

    @Override
    public void execute(Tuple input) {
        //这里由于上方下来的就是字符串,所以我们也是获取字符串就行 也可以getValues获取object 然后强转,如果传的是对象的话
        String allWord = input.getString(0);
        String[] words = allWord.split(" ");
        for(String w :words){
            collector.emit(new Values(w,1));
        }
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        //主要做个示范这个可以传多个数并且做多个声明
        declarer.declare(new Fields("word","num"));
    }
}

wordcountbolt类(这里木有reduce,但是bolt可以有依赖关系,所以我们可以将第二个bolt做reduce啊)

package com.lcy.storm.mapreduce;

import org.apache.storm.lambda.SerializableBiConsumer;
import org.apache.storm.lambda.SerializableConsumer;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IBasicBolt;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.IWindowedBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Tuple;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by: luo
 * date: 2019/7/23.
 * desc:
 */
public class WordCountBolt extends BaseRichBolt {
    Map<String,Integer> wcCountMap = new ConcurrentHashMap<>();
    @Override
    public void prepare(Map<String, Object> topoConf, TopologyContext context, OutputCollector collector) {

    }

    @Override
    public void execute(Tuple input) {
        String word = input.getString(0);
        Integer num = input.getInteger(1);
        if(wcCountMap.get(word)!=null){
            wcCountMap.put(word,wcCountMap.get(word)+num);
        }else {
            wcCountMap.put(word,num);
        }
        System.out.println(word+":count=" +wcCountMap.get(word));
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        //不输出也不需要去声明了
    }
}

可在本地先试运行下,之后可以将包提交到集群上运行查看效果。
项目github地址
在集群上使用 bin/storm jar storm-ops-1.0-SNAPSHOT.jar com.lcy.storm.mapreduce.MapReduceTopologyMain workcount 命令然后访问hadooop1:8080 查看是否提交了,之后可以试试那几个命令。
好了今天笔记就到这了,回头见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值