什麼是Storm?
Storm是:
• 快速且可擴展伸縮
• 容錯
• 確保消息能夠被處理
• 易於設置和操作
• 開源的分佈式實時計算系統
- 最初由Nathan Marz開發
- 使用Java 和 Clojure 編寫
Storm和Hadoop主要區別是實時和批處理的區別:
Tuple是Storm的數據模型,如['jdon',12346]
多個Tuple組成事件流:
Spout是讀取需要分析處理的數據源,然後轉爲Tuples,這些數據源可以是Web日誌、 API調用、數據庫等等。Spout相當於事件流的生產者。
Bolt 處理Tuples然後再創建新的Tuples流,Bolt相當於事件流的消費者。
Bolt 作爲真正業務處理者,主要實現大數據處理的核心功能,比如轉換數據,應用相應過濾器,計算和聚合數據(比如統計總和等等) 。
以Twitter的某個Tweet爲案例,看看Storm如何處理:
這些tweett貼內容是:“No Small Cell Lung #Cancer(沒有小細胞肺癌#癌症)” "An #OnCology Consult...."
這些貼被Spout讀取以後,產生Tuple,字段名是tweet,內容是"No Small Cell Lung #Cancer",格式類似:['No Small Cell Lung #Cancer',133221]。
然後進入被流 消費者Bolt進行處理,第一個Bolt是SplitSentence,將tuple內容進行分離,結果成爲:一個個單詞:"No" "Small" "Cell" "Lung" "#Cancer" ;然後經過第二個Bolt進行過濾HashTagFilter處理,Hash標籤是單詞中用#標註的,也就是Cancer;再經過HasTagCount計數,可以本地內存緩存這個計數結果,最後通過PrinterBolt打印出標籤單詞統計結果 。
我們使用Stom所要做的就是編制Spout和Bolt代碼:
public class RandomSentenceSpout extends BaseRichSpout {
SpoutOutputCollector collector;
Random random;
//讀入外部數據
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector = collector;
random = new Random();
}
//產生Tuple
public void nextTuple() {
String[] sentences = new String[] {
"No Small Cell Lung #Cancer",
"An #OnCology Consultant apple a day keeps the doctor away",
"four score and seven years ago",
"snow white and the seven dwarfs",
"i am at two with nature"
};
String tweet = sentences[random.nextInt(sentences.length)];
//定義字段名"tweet" 的值
collector.emit(new Values(tweet));
}
// 定義字段名"tweet"
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("tweet"));
}
@Override
public void ack(Object msgId) {}
@Override
public void fail(Object msgId) {}
}
下面是Bolt的代碼編寫:
public class SplitSentenceBolt extends BaseRichBolt {
OutputCollector collector;
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
}
@Override 消費者激活主要方法:分離成單個單詞
public void execute(Tuple input) {
for (String s : input.getString(0).split("\\s")) {
collector.emit(new Values(s));
}
}
@Override 定義新的字段名
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
最後是裝配運行Spout和Bolt的客戶端調用代碼:
public class WordCountTopology {
public static void main(String[] args) throws Exception {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("tweet", new RandomSentenceSpout(), 2);
builder.setBolt("split", new SplitSentenceBolt(), 4)
.shuffleGrouping("tweet")
.setNumTasks(8);
builder.setBolt("count", new WordCountBolt(), 6)
.fieldsGrouping("split", new Fields("word"));
..設置多個Bolt
Config config = new Config();
config.setNumWorkers(4);
StormSubmitter.submitTopology("wordcount", config, builder.createTopology());
// Local testing
//LocalCluster cluster = new LocalCluster();
// cluster.submitTopology("wordcount", config, builder.createTopology());
//Thread.sleep(10000);
//cluster.shutdown();
}
}
在這個代碼中定義了一些參數比如Works的數目是4,其含義在後面詳細分析
下面我們要將上面這段代碼發佈部署到Storm中,首先了解Storm物理架構圖:
Nimbus是一個主後臺處理器,主要負責:
1.發佈分發代碼
2.分配任務
3.監控失敗。
Supervisor是負責當前這個節點的後臺工作處理器的監聽。
Work類似Java的線程,採取JDK的Executor 。
下面開始將我們的代碼部署到這個網絡拓撲中:
將代碼Jar包上傳到Nimbus的inbox,包括所有的依賴包,然後提交。
Nimbus將保存在本地文件系統,然後開始配置網絡拓撲,分配開始拓撲。
見下圖:
Nimbus服務器將拓撲Jar 配置和結構下載到 Supervisor,負載平衡ZooKeeper分配某個特定的Supervisor服務器,而Supervisor開始基於配置分配Work,Work調用JDK的Executor啓動線程,開始任務處理。
下面是我們代碼對拓撲分配的參數示意圖: