Storm理解與入門

在使用一個框架前,我們需要知道這個框架能用來做什麼,可以解決我們什麼問題;

Storm是一個流式數據處理框架。我的理解是我們通過某種手段實時地將數據“發送”給框架(或者是框架自己主動獲取),數據在框架內被逐層處理,框架內的上下流程間以數據(稱之爲流)爲銜接;最終按照我們自定義邏輯處理熱數據或者離線數據(比如在線應用日誌,用戶行爲記錄等)的目標;

相關概念

Nimbus:即Storm的Master,負責資源分配和任務調度。一個Storm集羣只有一個Nimbus。

Supervisor:即Storm的Slave,負責接收Nimbus分配的任務,管理所有Worker,一個Supervisor節點中包含多個Worker進程。

Topology:計算拓撲,Storm 的拓撲是對實時計算應用邏輯的封裝,它的作用與 MapReduce 的任務(Job)很相似,區別在於 MapReduce 的一個 Job 在得到結果之後總會結束,而拓撲會一直在集羣中運行,直到你手動去終止它。拓撲還可以理解成由一系列通過數據流(Stream Grouping)相互關聯的 Spout 和 Bolt 組成的的拓撲結構。

Stream:數據流(Streams)是 Storm 中最核心的抽象概念。

Spout:數據源(Spout)是拓撲中數據流的來源。一般 Spout 會從一個外部的數據源讀取元組然後將他們發送到拓撲中。根據需求的不同,Spout 既可以定義爲可靠的數據源,也可以定義爲不可靠的數據源。一個可靠的 Spout能夠在它發送的元組處理失敗時重新發送該元組,以確保所有的元組都能得到正確的處理;相對應的,不可靠的 Spout 就不會在元組發送之後對元組進行任何其他的處理。一個 Spout可以發送多個數據流。

Bolt:拓撲中所有的數據處理均是由 Bolt 完成的。通過數據過濾(filtering)、函數處理(functions)、聚合(aggregations)、聯結(joins)、數據庫交互等功能,Bolt 幾乎能夠完成任何一種數據處理需求。一個 Bolt 可以實現簡單的數據流轉換,而更復雜的數據流變換通常需要使用多個 Bolt 並通過多個步驟完成。

附官網一張圖

水龍頭對應的Spout,其他節點對應的是Bolt,箭頭代表的是數據;

我們需要完成的工作就是Spout和Bolt的編寫,以及這張網(Topology)邏輯的編織

環境搭建

我們使用1.2.3版本

<!-- https://mvnrepository.com/artifact/org.apache.storm/storm-core -->
<dependency>
    <groupId>org.apache.storm</groupId>
    <artifactId>storm-core</artifactId>
    <version>1.2.3</version>
</dependency>

示例

個人覺得storm的接口風格和spring batch類似,將用戶自定義的操作抽象成一系列接口,這些接口在框架運行期間相互關聯(說得直接一點就是調用有先後順序,一些接口自定義讀取數據,另一些接口負責數據處理),所以知道這種模式對我們快速入門有很大的幫助;

編寫Spout

Spout主要邏輯是數據源的獲得,並將獲得的數據發送給下一級的Blot,

編寫Spout可以實現 IRichSpout 或繼承BaseRichSpout類,這裏我們採用繼承

package com.uu;

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.util.Map;
import java.util.Random;

public class DemoSpout extends BaseRichSpout {

    private SpoutOutputCollector spoutOutputCollector;
    int count = 0;

    /***
     * 框架開始時會被執行,代碼模式一般會把“SpoutOutputCollector”進行緩存到當前類,以便下一步“nextTuple”方法中調用
     * “SpoutOutputCollector”的emit 方法主要作用是將數據向下一級的“Blot”發送數據
     * @param map
     * @param topologyContext
     * @param spoutOutputCollector
     */
    @Override
    public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
        this.spoutOutputCollector = spoutOutputCollector;
    }

    /**
     * 該方法會在框架死循環中一直執行,這個方法裏可以讀取我們的資源(比如主動讀取一個網頁源碼,數據庫裏的增量數據等),
     * 並執行“SpoutOutputCollector”的'emit"方法將數據(封裝成”Tuple“)發送給下一個”Blot“<br/>
     *
     * 該示例是”發射“4次字符串給下一級的”Blot“
     */
    @Override
    public void nextTuple() {
        if(count < 4){
            spoutOutputCollector.emit(new Values("test-" + new Random(666).nextDouble()));
        }
        count ++;
    }

    /**
     * 聲明將數據綁定的key,以便下一個Blot通過”Tuple“獲得
     *
     * @param outputFieldsDeclarer
     */
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("log"));
    }
}

 

編寫Bolt

Blot主要就是處理Spout發送來的數據了,如果數據還需要下一級處理,則可以繼續發送給下一級Blot;

或者是輸出到文件?數據庫?緩存?這裏感覺沒有Hadoop那個reduce過程,數據都分散了(可能是我理解的不到位)

編寫Blot這裏我們還是採用繼承的方式來

package com.uu;

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;

public class DemoBlot extends BaseBasicBolt {

    /**
     * 該方法主要邏輯是接收上一級的數據,做自定義的處理<br/>
     *
     * 通過Tuple對象以及上一級聲明的field獲得數據,我們這裏只做打印(也可以做數據庫寫入等)
     *
     * @param tuple
     * @param basicOutputCollector
     */
    @Override
    public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
        String log = tuple.getStringByField("log");
        System.out.println("blot:" + log);
    }

    /***
     * 如果還有下一級處理邏輯,則處理方式跟 DemoSpout 一樣,聲明向下一級數據綁定的field
     *
     * @param outputFieldsDeclarer
     */
    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {

    }
}

組織Topology

Topology主要作用就是組織Spout與Blot的關係,比如這一次任務需要用哪一個Spout來獲得數據,並且指定好用哪些Blot來處理數據,並且各個Blot之間執行先後順序是怎樣的

還有一個就是這裏可以指定是本地單機執行任務還是提交集羣執行任務

package com.uu;

import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.topology.TopologyBuilder;

public class DemoMain {
    public static void main(String[] args) throws Exception {
        //創建 Topology
        TopologyBuilder topologyBuilder = new TopologyBuilder();

        //創建 spout
        DemoSpout spout = new DemoSpout();

        //創建 Bolt
        DemoBlot blot = new DemoBlot();

        topologyBuilder.setSpout("WebLogSpout", spout, 1);
        topologyBuilder.setBolt("WebLogBolt", blot, 2).shuffleGrouping("WebLogSpout");

        //    獲取配置
        Config config = new Config();
        //    設置workers
        config.setNumWorkers(2);

//demo裏我們採用本地集羣方式啓動程序
//如果程序是線上跑的話,需要安裝storm集羣,並以集羣的方式啓動
//集羣的部署,我們後面再用例子講解
        LocalCluster localCluster = new LocalCluster();
        localCluster.submitTopology("WebLogTopology", config, topologyBuilder.createTopology());
    }
}

如果是線環境,我們需要將我們編寫的應用打包成jar,上傳並提交storm集羣

輸出結果

blot:test-0.6974643684847707
blot:test-0.6974643684847707
blot:test-0.6974643684847707
blot:test-0.6974643684847707

這是一個最簡單的例子,有助於入門

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章