API簡介
Component組件
1)基本接口
(1)IComponent接口
(2)ISpout接口
(3)IRichSpout接口
(4)IStateSpout接口
(5)IRichStateSpout接口
(6)IBolt接口
(7)IRichBolt接口
(8)IBasicBolt接口
2)基本抽象類
(1)BaseComponent抽象類
(2)BaseRichSpout抽象類
(3)BaseRichBolt抽象類
(4)BaseTransactionalBolt抽象類
(5)BaseBasicBolt抽象類
spout水龍頭
Spout的最頂層抽象是ISpout接口
(1)Open()
是初始化方法
(2)close()
在該spout關閉前執行,但是並不能得到保證其一定被執行,kill -9時不執行,Storm kill {topoName} 時執行
(3)activate()
當Spout已經從失效模式中激活時被調用。該Spout的nextTuple()方法很快就會被調用。
(4)deactivate ()
當Spout已經失效時被調用。在Spout失效期間,nextTuple不會被調用。Spout將來可能會也可能不會被重新激活。
(5)nextTuple()
當調用nextTuple()方法時,Storm要求Spout發射元組到輸出收集器(OutputCollecctor)。NextTuple方法應該是非阻塞的,所以,如果Spout沒有元組可以發射,該方法應該返回。nextTuple()、ack()和fail()方法都在Spout任務的單一線程內緊密循環被調用。當沒有元組可以發射時,可以讓nextTuple去sleep很短的時間,例如1毫秒,這樣就不會浪費太多的CPU資源。
(6)ack()
成功處理tuple回調方法
(7)fail()
處理失敗tuple回調方法
原則:通常情況下(Shell和事務型的除外),實現一個Spout,可以直接實現接口IRichSpout,如果不想寫多餘的代碼,可以直接繼承BaseRichSpout。
bolt轉接頭
bolt的最頂層抽象是IBolt接口
(1)prepare()
prepare ()方法在集羣的工作進程內被初始化時被調用,提供了Bolt執行所需要的環境。
(2)execute()
接受一個tuple進行處理,也可emit數據到下一級組件。
(3)cleanup()
Cleanup方法當一個IBolt即將關閉時被調用。不能保證cleanup()方法一定會被調用,因爲Supervisor可以對集羣的工作進程使用kill -9命令強制殺死進程命令。
如果在本地模式下運行Storm,當拓撲被殺死的時候,可以保證cleanup()方法一定會被調用。
實現一個Bolt,可以實現IRichBolt接口或繼承BaseRichBolt,如果不想自己處理結果反饋,可以實現 IBasicBolt接口或繼承BaseBasicBolt,它實際上相當於自動做了prepare方法和collector.emit.ack(inputTuple)。
spout的tail特性
Storm可以實時監測文件數據,當文件數據變化時,Storm自動讀取。
以下是實時單詞統計案例,參考其中使用的api
採用maven構建項目
pom文件如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.storm/storm-core -->
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>${storm.version}</version>
</dependency>
</dependencies>
1)需求
實時統計發射到Storm框架中單詞的總數。
2)分析
設計一個topology,來實現對文檔裏面的單詞出現的頻率進行統計。
整個topology分爲三個部分:
(1)WordCountSpout:數據源,在已知的英文句子中,隨機發送一條句子出去。
(2)WordCountSplitBolt:負責將單行文本記錄(句子)切分成單詞
(3)WordCountBolt:負責對單詞的頻率進行累加
3)代碼
(1)創建spout
import java.util.Map;
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;
public class WordCountSpout extends BaseRichSpout {
private static final long serialVersionUID = 1L;
private SpoutOutputCollector collector;
@Override
public void nextTuple() {
// 1 發射模擬數據
collector.emit(new Values("i am ximen love jinlian"));
// 2 睡眠2秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
@Override
public void open(Map arg0, TopologyContext arg1, SpoutOutputCollector collector) {
this.collector = collector;
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("love"));
}
}
(2)創建切割單詞的bolt
import java.util.Map;
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;
public class WordCountSplitBolt extends BaseRichBolt {
private static final long serialVersionUID = 1L;
private OutputCollector collector;
@Override
public void execute(Tuple input) {
// 1 獲取傳遞過來的一行數據
String line = input.getString(0);
// 2 截取
String[] arrWords = line.split(" ");
// 3 發射
for (String word : arrWords) {
collector.emit(new Values(word, 1));
}
}
@SuppressWarnings("rawtypes")
@Override
public void prepare(Map arg0, TopologyContext arg1, OutputCollector collector) {
this.collector = collector;
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word", "num"));
}
}
(3)創建彙總單詞個數的bolt
import java.util.HashMap;
import java.util.Map;
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;
public class WordCountBolt extends BaseRichBolt {
private static final long serialVersionUID = 1L;
private Map<String, Integer> map = new HashMap<String, Integer>();
@Override
public void execute(Tuple input) {
// 1 獲取傳遞過來的數據
String word = input.getString(0);
Integer num = input.getInteger(1);
// 2 累加單詞
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:" + map.get(word));
}
@SuppressWarnings("rawtypes")
@Override
public void prepare(Map arg0, TopologyContext arg1, OutputCollector collector) {
}
@Override
public void declareOutputFields(OutputFieldsDeclarer arg0) {
// 不輸出
}
}
(4)創建程序的拓撲main
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) {
// 1、準備一個TopologyBuilder
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("WordCountSpout", new WordCountSpout(), 1);
builder.setBolt("WordCountSplitBolt", new WordCountSplitBolt(), 2).shuffleGrouping("WordCountSpout");
builder.setBolt("WordCountBolt", new WordCountBolt(), 4).fieldsGrouping("WordCountSplitBolt", new Fields("word"));
// 2、創建一個configuration,用來指定當前topology 需要的worker的數量
Config conf = new Config();
conf.setNumWorkers(2);
// 3、提交任務 -----兩種模式 本地模式和集羣模式
if (args.length > 0) {
try {
// 4 分佈式提交
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
} catch (Exception e) {
e.printStackTrace();
}
} else {
// 5 本地模式提交
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("wordcounttopology", conf, builder.createTopology());
}
}
}
(5)測試
發現132線程只處理單詞am和單詞love;169進程處理單詞i、ximen、jianlian。這就是分組的好處。
132 word:am num:1
132 word:love num:1
169 word:i num:1
169 word:ximen num:1
169 word:jinlian num:1