trident demo 1

做幾個storm的小程序來練手,買了一本Storm的書,但是書中的代碼運行都報錯,實在是心累啊。這本書出版較早,所用的storm和zookeeper的版本都較早,所以出現了一些方法已經不存在的問題。在我的艱難探索下,糾正了很多。書中的例子涉及內容很多,有kafka的,Cassandra的,Tina的,openfire的,等等等等。簡直就是百科全書啊,與其說是Storm的書,倒不如是介紹各種流行技術的書。

我打算以其中一個例子爲原型,稍作修改,將代碼整出來留作以後參考。書中第三章有個例子是:

通過全國各地醫院的傳感器上傳病症診斷報告,將時間戳經緯度和病症代碼上傳,storm接收這些信息並分析某地是否有某一疾病的爆發(一小時內該病症超過一個閾值的診斷出現認爲爆發疾病),一旦有就打印報警日誌。

第四章有個例子是:統計某一事件發生的趨勢,事件發生打印日誌kafka收集日誌,storm訂閱改主題收到日誌進行移動均值運算求出均值,判斷是否超過一個閾值,並向openfire的客戶端報告結果。

這兩個例子都不錯,第一個在運算上簡單一些,第二個用到了kafka和openfire更實用一些。我對第一個例子進行修改:

寫一個程序打印發病日誌內容爲時間,城市,病症id,然後kafka收集改日誌,storm訂閱kafka後面的處理和上面第一個例子一樣,最後如果檢測出某病症爆發不僅打印日誌而且發佈一個redis的主題,之後可以訂閱改主題進行後續操作使系統變得可擴展。

樣例的數據流如下:
這裏寫圖片描述

我們來分別解決每一個步驟:

模擬數據打印日誌同時發佈到kafka的在之前已經搞過了,如果遇到問題,可以參考http://user.qzone.qq.com/1572507002/blog/1497016120,這裏不再多說。然後就是最麻煩的地方了kafkaspout怎麼從kafka訂閱相關數據,我參考storm官網寫了好久的程序總是出錯,然後又參考了網上的一些代碼,發現都是老版本的storm包名都不是apache的。當時就放棄了,後來學了下trident感覺對storm進行了很好地抽象,代碼變得簡明瞭很多,於是就想用kafka的tridentspout來試試,經過我良久的探索,終於取得了成功。

首先是依賴我添加了如下四個依賴:

<dependency>
    <groupId>org.apache.storm</groupId>
    <artifactId>storm-core</artifactId>
    <version>1.1.0</version>
    <!--<scope>provided</scope>-->
</dependency>
<dependency>
    <groupId>org.apache.storm</groupId>
    <artifactId>storm-kafka</artifactId>
    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.11</artifactId>
    <version>0.11.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.11.0.0</version>
</dependency>

如果遇到log4j或slf4j的錯誤可能是沒有在引用kafka2.11的時候排除這幾個東西導致,按照上面排除三個依賴的依賴即可解決。如果遇到NoSuchMethodError:org.apache.kafka.common.network.NetworkSend這種問題是因爲沒有引用kafkaclients這個依賴導致。總之就是按照我這個依賴寫就不會有問題。

全部代碼:

Topology.java文件:

package topology;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.kafka.*;
import org.apache.storm.kafka.trident.OpaqueTridentKafkaSpout;
import org.apache.storm.kafka.trident.TridentKafkaConfig;
import org.apache.storm.trident.TridentTopology;
import org.apache.storm.trident.operation.*;
import org.apache.storm.trident.testing.FixedBatchSpout;
import org.apache.storm.trident.tuple.TridentTuple;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import java.util.Map;


/**
 * Created by Frank on 2017/7/16.
 */
public class Topology {
    publicstatic class DispatchAlert extends BaseFunction{
        privatestatic final long serialVersionUID =1L;
        privateint partitionIndex;
        publicvoid prepare(Map conf, TridentOperationContext context) {
            this.partitionIndex = context.getPartitionIndex();
        }
        publicvoid execute(TridentTuple tuple, TridentCollector collector) {
            System.out.println(partitionIndex);
            System.out.println(tuple);
        }
    }
    publicstatic StormTopology buildTopology(){
        BrokerHosts kafkaHosts = new ZkHosts("kafkaserverip:2181");
        TridentKafkaConfig spoutConf=new TridentKafkaConfig(kafkaHosts,"test");
        spoutConf.scheme=new StringMultiSchemeWithTopic();
        OpaqueTridentKafkaSpoutkafkaspout=new OpaqueTridentKafkaSpout(spoutConf);
        TridentTopology topology = new TridentTopology();

        topology.newStream("kafkaspout",kafkaspout)
                .each(new Fields("topic","str"), newDispatchAlert(), new Fields()); 
        return topology.build();
    }
    publicstatic void main(String[] args) throws Exception{
        Config conf = new Config();
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("cdc", conf, buildTopology());
    }
}

代碼解釋,主要分爲三個部分:DispatchAlert是一個Function用來打印執行的partitionid和tuple內容的;buildTopology是一個靜態方法返回整個拓撲結構,main方法將拓撲結構提交執行。其中buildTopology最重要,大部分代碼比較容易,第一行是指定server第二行是指定topic爲test,注意這個topic需要事先創建,否則會報類似KeeperErrorCode = NoNodefor /brokers/topics/test/partitions的錯誤。另外該函數倒數第二行topic和str是固定的值不能改成其他的,因爲schme指定的StringMultiSchemeWithTopic中設定了這兩個列名(分別代表topic和內容)。

運行後沒有報錯並最後有提示xxx:9092連接ed,9092是kafka的默認端口,雖然配置的是zookeeper的2181但實際是通過zookeeper找kafka連接的。看上去問題不大。

在服務器上查看9092的連接中看到有如下這麼個39.xx.xx.xx的ip,正是我山東聯通的ip。
這裏寫圖片描述

然後我們到kafka的服務器上運行腳本:

kafka-console-producer.sh –broker-listlocalhost:9092 –topic test

來手動向test這個主題發送點內容:
這裏寫圖片描述

嗯看來是成功用storm(trident)訂閱了kafka,不過我發現我發佈消息後有個1s左右,程序纔打印,我以爲是網絡問題,後來覺得不太可能,然後沒想明白就睡了,今天我想到是爲啥了,應該是trident將多個tuple聚合成batch的緣故,所以我嘗試在上面的腳本中狂點六七次回車相當於短時間內發多個空消息,然後程序果然是演示了1s左右瞬間彈出所有的消息。
這裏寫圖片描述
於是完成了第二個橫向的箭頭,也是最容易失敗的一個點,剩下的所有會在下一篇中全部展示。

發佈了40 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章