留给刚开始学习的自己一点笔记
常用命令行操作
- bin/storm nimous & 后台启动nimous
- bin/storm supervisor & 后台启动supervisor
- bin/storm ui & 后台启动ui(默认端口号8080)
- bin/storm logviewer & 提供一个web接口查看storm日志文件
- bin/storm list 列出正在运行的拓扑及其状态
- bin/storm jar 【jar路径】 【拓扑包名。拓扑类名】 【拓扑名称】 启动storm程序
- bin/storm kill topology-name [-w wait-time-secs] 杀死名为topology-name的拓扑,-w等待多久后杀死
- bin/storm active topology-name 激活指定的拓扑spout
- bin/storm deactive topology-name 禁用指定的拓扑spout
- bin/storm help 打印一条帮助消息或者可用命令列表
storm和hadoop的区别
- storm用于实时计算;hadoop用于离线计算
- storm处理的数据保存在内存中,源源不断;hadoop保存在文件系统中,一批一批处理
- storm的数据通过网络传输进来;hadoop的数据保存在磁盘中
- storm与hadoop的编程模型相似
storm | hadoop | |
---|---|---|
角色 | Nimbus | JobTracker |
Supervisor | TaskTracker | |
Woker | Child | |
应用名称 | Topology | Job |
编程接口 | Spout / Bolt | Mapper / Reducer |
storm的编程模型
Tuple:Tuple是Storm中的主要数据结构。它是有序元素的列表。默认情况下,Tuple支持所有数据类型。通常,它被建模为一组逗号分隔的值,并传递到Storm集群。
Stream:流是元组的无序序列。
Spouts :流的源。通常,Storm从原始数据源(如Twitter Streaming API,Apache Kafka队列,Kestrel队列等)接受输入数据。否则,您可以编写spouts以从数据源读取数据。“ISpout”是实现spouts的核心接口,一些特定的接口是IRichSpout,BaseRichSpout,KafkaSpout等。
Bolts:Bolts是逻辑处理单元。Spouts将数据传递到Bolts和Bolts过程,并产生新的输出流。Bolts可以执行过滤,聚合,加入,与数据源和数据库交互的操作。Bolts接收数据并发射到一个或多个Bolts。 “IBolt”是实现Bolts的核心接口。一些常见的接口是IRichBolt,IBasicBolt等。
storm的核心组件
Nimbus(主节点):Nimbus是Storm集群的主节点。集群中的所有其他节点称为工作节点。主节点负责在所有工作节点之间分发数据,向工作节点分配任务和监视故障。
Supervisor(工作节点):遵循指令的节点被称为Supervisors。Supervisor有多个工作进程,它管理工作进程以完成由nimbus分配的任务。
Worker process(工作进程) 工作进程将执行与特定拓扑相关的任务。工作进程不会自己运行任务,而是创建执行器并要求他们执行特定的任务。工作进程将有多个执行器。
Executor(执行者):执行器只是工作进程产生的单个线程。执行器运行一个或多个任务,但仅用于特定的spout或bolt。
Task(任务):任务执行实际的数据处理。所以,它是一个spout或bolt。
ZooKeeper框架:Apache的ZooKeeper的是使用群集(节点组)自己和维护具有强大的同步技术共享数据之间进行协调的服务。Nimbus是无状态的,所以它依赖于ZooKeeper来监视工作节点的状态。
ZooKeeper的帮助supervisor与nimbus交互。它负责维持nimbus,supervisor的状态。
Nimbus 主控节点,Supervisor 一台台主机节点,Supervisor 里有多个 worker (进程),worker 里有多个 executor(线程),executor里有多个任务。
总结:Nimbus下命令(分配任务),zk监督执行(worker、Supervisor 心跳监控),Supervisor下载代码,创建worker 和线程等
api简介
1. component组件
-
基本接口
- IComponent 接口
- ISpout 接口
- IRichSpout 接口
- IStateSpout 接口
- IRichStateSpout 接口
- IBolt 接口
- IRichBolt 接口
- IBasicBolt 接口 基本抽象类
- BaseComponent 抽象类
- baseRichSpout 抽象类
- BaseRichBolt 抽象类
- BaseTransactionalBolt 抽象类
- BaseBasicBolt 抽象类
2. spout
spout的最顶层抽象是ISpout接口
- open()初始化
- close()在该spout关闭前执行,但是并不能得到保证其一定被执行,kill -9 时不执行,storm kill{topoName}时执行
- active()当spout已经从失效模式中激活时被调用。该spout的nextTuple()方法很快就被调用
- deaactive()当spout已经失效时被调用。
- nextTuple()发射元组到输出收集器
- ack()成功处理tuple回调方法
(7) fail()处理失败tuple回调方法
原则:通常情况下(Shell 和事务型的除外),实现一个Spout,可以直接实现接口IRichSpout,如果不想写多余的代码,可以直接继承BaseRichSpout。。
3. bolt
bolt的最顶层抽象是ISpout接口
- prepare()初始化时,提供了Bolt执行所需要的环境
- execute()接受一个tuple进行业务处理,也可emit数据到下-级组件。
- cleanup()清场关闭
4. spout的tail特性
storm可以实时监测文件数据,当文件数据变化时,storm自动读取
分组策略
stream grouping用来定义一个stream应该如何分配给Bolts. 上面的多个Executors (多线程、
多并发)。
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是-样的效果。在多线程情况下不平均分配。
- Direct Grouping: 直接分组,这是-种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect 方法来发射。消息处理者可以通过TopologyContext来获取处理它的消息的task的id (OutputCollector.emit 方法也会返回task的id)。
- Local or shuffle grouping:如果目标bolt有一个或者多个task在同一一个工作进程中,tuple将会被随机发送给这些tasks。否则,和普通的Shuffle Grouping行为一致。
并发度
并发度:用户指定一个任务,可以被多个线程执行, 并发度的数量等于线程executor的数量。
Task就是具体的处理逻辑对象,一个executor线程可以执行-一个或多个tasks,但一般默认每个executor只执行一个task,所以我们往往认为task就是执行线程,其实不是。
Task代表最大并发度,一个component的task 数是不会改变的,但是一个componet的
executer数目是会发生变化的( storm rebalance命令),task 数>=executor数, executor 数代表实际并发数。
Wordcount例子
设计一个topology,来实现对文件里面的单词出现的频率进行统计
整个topology分为三个部分: .
(1) WordCountSpout:数据源,读取文件一行行数据。
(2) WordCountsplitBolt:负责将单行文本记录切分成单词。
(3) WordCountBolt:负责对单词的频率进行累加工
WordCountSpout:
package wordCount;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
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.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.Map;
public class wordCountSpout extends BaseRichSpout {
private SpoutOutputCollector collector;
private BufferedReader reader;
private String str;
@Override
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
this.collector = collector;
try {
this.reader = new BufferedReader(new InputStreamReader(new FileInputStream("e:/wc.log")));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void nextTuple() {
try{
//发送数据
while((str = reader.readLine()) != null){
collector.emit(new Values(str));
Thread.sleep(500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("line"));
}
}
wordCountSplitBolt:
package wordCount;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
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;
public class wordCountSplitBolt extends BaseRichBolt {
private OutputCollector collector;
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector collector) {
this.collector = collector;
}
@Override
public void execute(Tuple input) {
//接收数据
String line = input.getString(0);//Fields("line")
//截取
String[] splits = line.split("\t");
//发出去
for(String word : splits){
collector.emit(new Values(word,1));
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
//声明字段
declarer.declare(new Fields("word","num"));
}
}
wordCountBolt:
package wordCount;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Tuple;
import java.util.HashMap;
import java.util.Map;
public class wordCountBolt extends BaseRichBolt {
//单词为key;单词出现次数为value
private Map<String , Integer> map = new HashMap<>();
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
}
@Override
public void execute(Tuple input) {
//获取传递过来的数据
String word = input.getString(0);
Integer num = input.getInteger(1);
//业务处理
if(map.containsKey(word)){
Integer count = map.get(word);
map.put(word,count+num);
}else {
map.put(word,num);
}
//控制台打印
System.err.println(Thread.currentThread().getId()+" word:"+ word+" num:"+num);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
}
}
wordCountMain:
package wordCount;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;
public class wordCountMain {
public static void main(String[] args) {
//创建拓扑对象
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("wordCountSpout",new wordCountSpout(),1);
builder.setBolt("wordCountSplitBolt",new wordCountSplitBolt(),4).fieldsGrouping("WordCountSpout",new Fields("love"));
builder.setBolt("wordCountBolt",new wordCountBolt(),1).fieldsGrouping("wordCountSplitBolt",new Fields("word"));
Config config = new Config();
config.setNumWorkers(2);
//提交程序
if(args.length > 0){
//集群提交
try {
StormSubmitter.submitTopology("wordCountTopology" ,config,builder.createTopology());
} catch (Exception e) {
e.printStackTrace();
}
}else {
//本地提交
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("wordCountTopology",config,builder.createTopology());
}
}
}
PV例子(使用基本接口)
UVSpout:(读数据)
package UV;
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.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.Map;
public class UVSpout implements IRichSpout {
private SpoutOutputCollector SpoutOutputCollector;
private BufferedReader reader;
@Override
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
this.SpoutOutputCollector =SpoutOutputCollector;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream("e:/website2.log")));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
@Override
public void close() {
}
@Override
public void activate() {
}
@Override
public void deactivate() {
}
private String str = null;
@Override
public void nextTuple() {
try{
//发送数据
while((str = reader.readLine()) != null){
SpoutOutputCollector.emit(new Values(str));
Thread.sleep(500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void ack(Object o) {
}
@Override
public void fail(Object o) {
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("log"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
UVSplitBolt:(截取ip,计数为1)
package UV;
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;
public class UVSplitBolt implements IRichBolt {
private OutputCollector OutputCollector;
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.OutputCollector = OutputCollector;
}
@Override
public void execute(Tuple input) {
//获取数据
String line = input.getString(0);
//截取
String[] splits = line.split("\t");
String ip = splits[3];
//发出去
OutputCollector.emit(new Values(ip,1));
}
@Override
public void cleanup() {
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("ip","num"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
UVSumBolt:(存入map,累加求总数)
package UV;
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.Tuple;
import java.util.HashMap;
import java.util.Map;
public class UVSumBolt implements IRichBolt {
private Map<String,Integer> map = new HashMap<>();
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
}
@Override
public void execute(Tuple input) {
String ip = input.getString(0);
Integer num = input.getInteger(1);
if (map.containsKey(ip)){
Integer count = map.get(ip);
map.put(ip,count+num);
}else {
map.put(ip,num);
}
System.out.println(ip+" "+num);
}
@Override
public void cleanup() {
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
UVMain :
package UV;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.topology.TopologyBuilder;
public class UVMain {
public static void main(String[] args) {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("UVSpout",new UVSpout(),1);
builder.setBolt("UVSplitBolt",new UVSplitBolt(),4).shuffleGrouping("UVSpout");
builder.setBolt("UVSumBolt",new UVSumBolt(),1).shuffleGrouping("UVSplitBolt");
Config config = new Config();
config.setNumWorkers(2);
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("uvtopology",config,builder.createTopology());
}
}