什麼是Apache Storm
Apache Storm是一個分佈式實時大數據處理系統。Storm設計用於在容錯和水平可擴展方法中處理大量數據。它是一個流數據框架,具有最高的攝取率。雖然Storm是無狀態的,它通過Apache ZooKeeper管理分佈式環境和集羣狀態。它很簡單,您可以並行地對實時數據執行各種操作。
Apache Storm繼續成爲實時數據分析的領導者。Storm易於設置和操作,並且它保證每個消息將通過拓撲至少處理一次。
storm優點
- 編程簡單:開發人員只需要關注應用邏輯,而且跟Hadoop類似,Storm提供的編程原語也很簡單
- 高性能,低延遲:可以應用於廣告搜索引擎這種要求對廣告主的操作進行實時響應的場景。
- 分佈式:可以輕鬆應對數據量大,單機搞不定的場景
- 可擴展: 隨着業務發展,數據量和計算量越來越大,系統可水平擴展
- 容錯:單個節點掛了不影響應用
- 消息不丟失:保證消息處理
storm集羣架構
Nimbus(主節點): Nimbus是Storm集羣的主節點。集羣中的所有其他節點稱爲工作節點。主節點負責在所有工作節點之間分發數據,向工作節點分配任務和監視故障。
Supervisor(工作節點): 遵循指令的節點被稱爲Supervisors。Supervisor有多個工作進程,它管理工作進程以完成由nimbus分配的任務。
Worker process(工作進程): 工作進程將執行與特定拓撲相關的任務。工作進程不會自己運行任務,而是創建執行器並要求他們執行特定的任務。工作進程將有多個執行器。
Executor(執行者): 執行器只是工作進程產生的單個線程。執行器運行一個或多個任務,但僅用於特定的spout或bolt。
Task(任務): 任務執行實際的數據處理。所以,它是一個spout或bolt。
ZooKeeper framework(ZooKeeper框架): Apache的ZooKeeper的是使用羣集(節點組)自己和維護具有強大的同步技術共享數據之間進行協調的服務。Nimbus是無狀態的,所以它依賴於ZooKeeper來監視工作節點的狀態。
ZooKeeper的幫助supervisor與nimbus交互。它負責維持nimbus,supervisor的狀態。
Storm雖然不是完全無狀態的。它將其狀態存儲在Apache ZooKeeper中。由於狀態在Apache ZooKeeper中可用,故障的網絡可以重新啓動,並從它離開的地方工作。通常,像monit這樣的服務監視工具將監視Nimbus,並在出現任何故障時重新啓動它。
storm基礎說明
可以簡單的理解爲storm是把一個任務(Topology)分成多個小單元處理,每個小單元(bolts)可以設置一個或多個線程.
TopologyBuilder: 創建拓撲(打包實時處理邏輯)
- setSpout(String id, IRichSpout spout, Number parallelism_hint)
- setBolt(String id, IRichBolt bolt, Number parallelism_hint).shuffleGrouping()
- createTopology()
parallelism_hint: 線程個數
shuffleGrouping: 隨機分組(分組模式)
Spout: 實現一個IRichSpout接口
- open() 初始化你的數據源.
- nextTuple() 通過收集器發出生成的數據。
- close() spout關閉
- declareOutputFields() 聲明元組輸出模式.(即輸出數據類型)
- ack() 確認處理
- fail() 不處理或不重新處理
Bolt: 實現IRichBolt接口
- prepare() 執行器將運行此方法來初始化spout。
- execute() 處理單個元組(數據)
- cleanup() spout關閉時使用
- declareOutputFields() 聲明元組輸出模式.(即輸出數據類型)
storm簡單代碼
Sport:
public class FakeCallLogReaderSpout implements IRichSpout {
//Create instance for SpoutOutputCollector which passes tuples to bolt.
private SpoutOutputCollector collector;
private boolean completed = false;
//Create instance for TopologyContext which contains topology data.
private TopologyContext context;
//Create instance for Random class.
private Random randomGenerator = new Random();
private Integer idx = 0;
@Override
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.context = context;
this.collector = collector;
}
@Override
public void nextTuple() {
if(this.idx <= 1000) {
List<String> mobileNumbers = new ArrayList<String>();
mobileNumbers.add("1234123401");
mobileNumbers.add("1234123402");
mobileNumbers.add("1234123403");
mobileNumbers.add("1234123404");
Integer localIdx = 0;
while(localIdx++ < 100 && this.idx++ < 1000) {
String fromMobileNumber = mobileNumbers.get(randomGenerator.nextInt(4));
String toMobileNumber = mobileNumbers.get(randomGenerator.nextInt(4));
while(fromMobileNumber == toMobileNumber) {
toMobileNumber = mobileNumbers.get(randomGenerator.nextInt(4));
}
Integer duration = randomGenerator.nextInt(60);
this.collector.emit(new Values(fromMobileNumber, toMobileNumber, duration));
}
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("from", "to", "duration"));
}
//Override all the interface methods
@Override
public void close() {}
public boolean isDistributed() {
return false;
}
@Override
public void activate() {}
@Override
public void deactivate() {}
@Override
public void ack(Object msgId) {}
@Override
public void fail(Object msgId) {}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
CallLogCreatorBolt
public class CallLogCreatorBolt implements IRichBolt {
//Create instance for OutputCollector which collects and emits tuples to produce output
private OutputCollector collector;
@Override
public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
}
@Override
public void execute(Tuple tuple) {
String from = tuple.getString(0);
String to = tuple.getString(1);
Integer duration = tuple.getInteger(2);
collector.emit(new Values(from + " - " + to, duration));
}
@Override
public void cleanup() {}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("call", "duration"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
TopologyBuilder
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("call-log-reader-spout", new FakeCallLogReaderSpout());
builder.setBolt("call-log-creator-bolt", new CallLogCreatorBolt(),1)
.shuffleGrouping("call-log-reader-spout");
builder.createTopology()