标签(空格分隔): hadoop
重点内容
storm的核心组件
…编程模型
…task 并发度
storm是什么
storm是一个流式计算框架,神马是流式计算呢,就是针对于离线计算数据的延时性的补充,人家快啊,这样就既可以有实时的数据,也有历史的(mapreduce,spark)统计数据,两手抓嘛,心里才能安稳不是。
核心组件
我们还是按图索骥,先上一下我们滴下面这个图欣赏一下(欣赏不来没关系您可以画个更美的我回头贴上)。
storm角色及流程图
以上是storm的相关组件及编程模型的角色,我们从上到下来look一下都是神马。
nimbus:可以理解为任务管理员,通过zk完成资源分配和任务的分配。(这年头都是可以ha滴)
supervisor:这个是进程管理器,就是管理本机上的进程,在这里就是管理work用滴。
worker: worker process 就是工作进程,这个工作进程里面主要包含了几个角色,spout,bolt这个主要是编程时用到的类。回头我们在编程里面会介绍下这些角色类之间的关系。
编程模型角色
编程角色图
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>
类结构如下
入口类
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 查看是否提交了,之后可以试试那几个命令。
好了今天笔记就到这了,回头见