本地模式
在本地模式下,Storm拓撲結構執行在本地計算機的單一JVM程式上。這個模式用於開發、測試以及除錯,因為這是觀察所有元件如何協同工作的最簡單方法。在這種模式下,我們可以調整引數,觀察我們的拓撲結構如何在不同的Storm配置環境下執行。要在本地模式下執行,我們要下載Storm開發依賴,以便用來開發並測試我們的拓撲結構。我們建立了第一個Storm工程以後,很快就會明白如何使用本地模式了。 NOTE: 在本地模式下,跟在叢集環境執行很像。不過很有必要確認一下所有元件都是執行緒安全的,因為當把它們部署到遠端模式時它們可能會執行在不同的JVM程式甚至不同的物理機上,這個時候它們之間沒有直接的通訊或共享記憶體。
遠端模式
在遠端模式下,我們向Storm叢集提交拓撲,它通常由許多執行在不同機器上的流程組成。遠端模式不會出現除錯資訊, 因此它也稱作生產模式。不過在單一開發機上建立一個Storm叢集是一個好主意,可以在部署到生產環境之前,用來確認拓撲在叢集環境下沒有任何問題。
常用Java api
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抽象類
複製程式碼
建立資料來源(Spouts )
package com.qxw.spout;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
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;
/**
* 資料來源 spout
* @author qxw
* @data 2018年9月17日上午11:21:00
*
* 申明資料來源的方式:繼承BaseRichSpout類 , 重寫需要的方法。實現IRichSpout介面 重寫所有的方法
*/
public class DataSource extends BaseRichSpout {
private static final long serialVersionUID = 1L;
private SpoutOutputCollector collector;
private static final Map<Integer, String> map = new HashMap<Integer, String>();
static {
map.put(0, "java");
map.put(1, "php");
map.put(2, "groovy");
map.put(3, "python");
map.put(4, "ruby");
}
/**
* 初始化方法
*/
@Override
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector = collector;
}
/**
* 輪詢tuple 傳送資料
*/
@Override
public void nextTuple() {
//這裡可以查詢資料庫 或者讀取訊息佇列中的資料、測試使用map替代
final Random r = new Random();
int num = r.nextInt(5);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//傳送單詞到下一個拓撲節點
this.collector.emit(new Values(map.get(num)));
}
/**
* 宣告傳送資料的名稱
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
//指定名稱 用於下一個節店取值時使用
declarer.declare(new Fields("data"));
}
/**
* 在該spout關閉前執行,但是並不能得到保證其一定被執行
*/
@Override
public void close() {
System.out.println("spout關閉前執行");
}
/**
* 當Spout已經從失效模式中啟用時被呼叫。該Spout的nextTuple()方法很快就會被呼叫。
*/
@Override
public void activate() {
System.out.println("當Spout已經從失效模式中啟用時被呼叫");
}
/**
* 當Spout已經失效時被呼叫。在Spout失效期間,nextTuple不會被呼叫。Spout將來可能會也可能不會被重新啟用。
*/
@Override
public void deactivate() {
System.out.println("當Spout已經失效時被呼叫");
}
/**
* 成功處理tuple回撥方法
*/
@Override
public void ack(Object paramObject) {
System.out.println("成功處理tuple回撥方法");
}
/**
* 處理失敗tuple回撥方法
*/
@Override
public void fail(Object paramObject) {
System.out.println("paramObject");
}
}
複製程式碼
資料流處理元件
package com.qxw.bolt;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
/**
* 資料庫流處理元件
*
* 列印出輸處理的bolt
* 實現方式:繼承BaseBasicBolt類 或實現IBasicBolt
* @author qxw
* @data 2018年9月17日上午11:36:07
*/
public class OutBolt extends BaseBasicBolt {
private static final long serialVersionUID = 1L;
/**
* 接受一個tuple進行處理,也可傳送資料到下一級元件
*/
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
////獲取上一個元件所宣告的Field
String value=input.getStringByField("data");
System.out.println("資料來源傳送的data: "+value);
//傳送到下一個元件
collector.emit(new Values(value));
}
/**
* 宣告傳送資料的名稱
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
//可同時傳送多個Field
declarer.declare(new Fields("outdata"));
}
}
複製程式碼
package com.qxw.bolt;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Tuple;
/**
* 資料庫流處理元件
*
* 列印出輸處理的bolt
* 實現方式:繼承BaseBasicBolt類 或實現IBasicBolt
* @author qxw
* @data 2018年9月17日上午11:36:07
*/
public class OutBolt2 extends BaseBasicBolt {
private static final long serialVersionUID = 1L;
/**
* 接受一個tuple進行處理,也可傳送資料到下一級元件
*/
@Override
public void execute(Tuple input, BasicOutputCollector collector) {
////獲取上一個元件所宣告的Field
String value=input.getStringByField("outdata");
System.out.println("接收OutBolt資料庫流處理元件傳送的值: "+value);
}
/**
* 宣告傳送資料的名稱
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
複製程式碼
構造拓撲圖
package com.qxw.topology;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.topology.TopologyBuilder;
import com.qxw.bolt.OutBolt;
import com.qxw.bolt.OutBolt2;
import com.qxw.spout.DataSource;
public class TopologyTest {
public static void main(String[] args) throws Exception {
//配置
Config cfg = new Config();
cfg.setNumWorkers(2);//指定工作程式數 (jvm數量,分散式環境下可用,本地模式設定無意義)
cfg.setDebug(true);
//構造拓撲流程圖
TopologyBuilder builder = new TopologyBuilder();
//設定資料來源
builder.setSpout("dataSource", new DataSource());
//設定資料建流處理元件
builder.setBolt("out-bolt", new OutBolt()).shuffleGrouping("dataSource");//隨機分組
builder.setBolt("out-bol2", new OutBolt2()).shuffleGrouping("out-bolt");
//1 本地模式
LocalCluster cluster = new LocalCluster();
//提交拓撲圖 會一直輪詢執行
cluster.submitTopology("topo", cfg, builder.createTopology());
//2 叢集模式
// StormSubmitter.submitTopology("topo", cfg, builder.createTopology());
}
}
複製程式碼
storm實現單詞計數器統計
資料來源Spout
package com.qxw.wordCount;
import java.util.Map;
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;
/**
* 資料來源
* @author qxw
* @data 2018年9月18日上午11:58:35
*/
public class WordSpout implements IRichSpout{
private static final long serialVersionUID = 1L;
private SpoutOutputCollector collector;
private int index=0;
private final String[] lines = {
"long long ago I like playing with cat",
"playing with cat make me happy",
"I feel happy to be with you",
"you give me courage",
"I like to be together with you",
"long long ago I like you"
};
//初始化
@Override
public void open(Map conf, TopologyContext context,SpoutOutputCollector collector) {
this.collector=collector;
}
//傳送資料
@Override
public void nextTuple() {
this.collector.emit(new Values(lines[index]));
index++;
if(index>=lines.length){
index=0;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("line"));
}
@Override
public void close() {
// TODO Auto-generated method stub
}
@Override
public void activate() {
// TODO Auto-generated method stub
}
@Override
public void deactivate() {
// TODO Auto-generated method stub
}
@Override
public void ack(Object msgId) {
// TODO Auto-generated method stub
}
@Override
public void fail(Object msgId) {
// TODO Auto-generated method stub
}
@Override
public Map<String, Object> getComponentConfiguration() {
// TODO Auto-generated method stub
return null;
}
}
複製程式碼
切割元件
public class WordSplitBolt implements IRichBolt {
private static final long serialVersionUID = 1L;
private OutputCollector collector;
@Override
public void prepare(Map stormConf, TopologyContext context,OutputCollector collector) {
this.collector = collector;
}
/**
* 這個函式也會被不斷執行,但它的資料來自於上游。
* 這裡將文字行分割為單詞,併傳送
* @param tuple
*/
@Override
public void execute(Tuple input) {
String line = input.getStringByField("line");
String[] words = line.split(" ");
for(String word : words){
this.collector.emit(new Values(word));
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
@Override
public Map<String, Object> getComponentConfiguration() {
// TODO Auto-generated method stub
return null;
}
}
複製程式碼
統計元件
public class WordCountBolt implements IRichBolt{
private static final long serialVersionUID = 1L;
private OutputCollector collector;
private HashMap<String, Long> counts=null;
/**
* 初始化放方法
*/
@Override
public void prepare(Map stormConf, TopologyContext context,OutputCollector collector) {
this.collector = collector;
this.counts=new HashMap<String, Long>();
}
/**
* 統計單詞出現的次數 一般是儲存到資料庫
*/
@Override
public void execute(Tuple input) {
String word=input.getStringByField("word");
Long count = 1L;
if(counts.containsKey(word)){
count = counts.get(word) + 1;
}
counts.put(word, count);
System.out.println("統計單詞:"+word+" 出現次數: "+count);
this.collector.emit(new Values(word, count));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word","count"));
}
@Override
public void cleanup() {
// TODO Auto-generated method stub
}
@Override
public Map<String, Object> getComponentConfiguration() {
// TODO Auto-generated method stub
return null;
}
}
複製程式碼
輸出元件
public class WordReportBolt implements IRichBolt {
private static final long serialVersionUID = 1L;
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
}
@Override
public void execute(Tuple input) {
String word=input.getStringByField("word");
Long count=input.getLongByField("count");
System.out.printf("實時統計單詞出現次數 "+"%s\t%d\n", word, count);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// TODO Auto-generated method stub
}
@Override
public void cleanup() {
}
@Override
public Map<String, Object> getComponentConfiguration() {
// TODO Auto-generated method stub
return null;
}
}
複製程式碼
Topology主函式類
public class WordTopology {
public static void main(String[] args) throws InterruptedException {
// 組建拓撲,並使用流分組
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("WordSpout", new WordSpout());
builder.setBolt("WordSplitBolt", new WordSplitBolt(),5).shuffleGrouping("WordSpout");
builder.setBolt("WordCountBolt", new WordCountBolt(),5).fieldsGrouping("WordSplitBolt", new Fields("word"));
builder.setBolt("WordReportBolt", new WordReportBolt(),10).globalGrouping("WordCountBolt");
//配置
Config cfg = new Config();
cfg.setDebug(false);
LocalCluster cluster = new LocalCluster();
//提交拓撲圖 會一直輪詢執行
cluster.submitTopology("wordcount-topo", cfg, builder.createTopology());
}
}
複製程式碼