storm 微批處理高級API Trident

  1. storm Trident 概述
    1.1. Apply Locally本地操作:操作都應用在本地節點的Batch上,不會產生網絡傳輸
    1.2. Functions:函數操作
    1.3. Filters:過濾操作
    1.4. PartitionAggregate
    1.5. Aggragation聚合操作
    1.6. grouped streams
    1.7. Merge和Joins:
  2. 什麼是Storm Trident ?

Trident是基於Storm進行實時留處理的高級抽象,提供了對實時流4的聚集,投影,過濾等操作,從而大大減少了開發Storm程序的工作量。Trident還提供了針對數據庫或則其他持久化存儲的有狀態的,增量的更新操作的原語。

若我們要開發一個對文本中的詞頻進行統計的程序,使用Storm框架的話我們需要開發三個Storm組件:

1.一個Spout負責接收kafka數據

2.一個Bolt對數據進行解析,將解析結果以word字段發送給下游的Bolt

3.一個Bolt對詞頻進行統計,把統計結果記錄在count字段並存儲

如果使用Trident我們可以使用一下代碼完成上述操作:

import com.alibaba.fastjson.JSONObject;
import kafka.Kafka;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.kafka.*;
import org.apache.storm.kafka.trident.TransactionalTridentKafkaSpout;
import org.apache.storm.kafka.trident.TridentKafkaConfig;
import org.apache.storm.spout.SchemeAsMultiScheme;
import org.apache.storm.trident.Stream;
import org.apache.storm.trident.TridentTopology;

import org.apache.storm.trident.operation.BaseFilter;
import org.apache.storm.trident.operation.MapFunction;
import org.apache.storm.trident.tuple.TridentTuple;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StormTridentTest {

public static void main(String[] args) {
    Logger logger=LoggerFactory.getLogger(StormTridentTest.class);
    TridentTopology topology=new TridentTopology();
    BrokerHosts brokerHosts =new ZkHosts("localhost:2181");
     
    //Kafka spout 相關配置
    String topic="testtest";
    TridentKafkaConfig config=new TridentKafkaConfig(brokerHosts,topic,"trid");
    config.scheme=new SchemeAsMultiScheme(new StringScheme());

    //trident kafka spout
    TransactionalTridentKafkaSpout spout=new TransactionalTridentKafkaSpout(config);

    //create trident kafka stream,對數據進行解析,計數
    Stream tickteAdd=topology.newStream("spout",spout)
            .map(new MapFunction() {
                @Override
                public Values execute(TridentTuple tridentTuple) {
                    String data=tridentTuple.getString(0);
                    JSONObject dataJson= JSONObject.parseObject(data);
                    if(dataJson==null){
                        logger.info("xxs"+dataJson);
                        return (new Values("",0));
                    }
                    String word=dataJson.getString("word");
                    int cnt=dataJson.getIntValue("cnt");
                    return (new Values(word,cnt));
                }
            },new Fields("word","cnt")).each(new Fields("word","cnt"), new BaseFilter() {
                private  final Logger logger = LoggerFactory.getLogger(this.getClass());
                @Override
                public boolean isKeep(TridentTuple tridentTuple) {
                    logger.info("cnt:"+tridentTuple);
                    return true;
                }
            });
    Config conf = new Config();
    LocalCluster clu = new LocalCluster();
    clu.submitTopology("mytopology", conf, topology.build());
}}
  1. storm Trident 概述
    Storm Trident中的核心數據模型就是“Stream”,也就是說,Storm Trident處理的是Stream,但是實際上Stream是被成批處理的,Stream被切分成一個個的Batch分佈到集羣中,所有應用在Stream上的函數最終會應用到每個節點的Batch中,實現並行計算,具體如下圖所示:
    這裏寫圖片描述

在Trident中有五種操作類型:

Apply Locally:本地操作,所有操作應用在本地節點數據上,不會產生網絡傳輸
Repartitioning:數據流重定向,單純的改變數據流向,不會改變數據內容,這部分會有網絡傳輸
Aggragation:聚合操作,會有網絡傳輸
Grouped streams上的操作
Merge和Join
1.1. Apply Locally本地操作:操作都應用在本地節點的Batch上,不會產生網絡傳輸
1.2. Functions:函數操作
函數的作用是接收一個tuple(需指定接收tuple的哪個字段),輸出0個或多個tuples。輸出的新字段值會被追加到原始輸入tuple的後面,如果一個function不輸出tuple,那就意味這這個tuple被過濾掉了,如下是實現的一個MapFunction,這個Function的功能就是遍歷並解析每個tuple:
這裏寫圖片描述
1.3. Filters:過濾操作
Filters很簡單,接收一個tuple並決定是否保留這個tuple。舉個例子,定義一個Filter:這裏寫圖片描述
1.4. PartitionAggregate

PartitionAggregate的作用對每個Partition中的tuple進行聚合,與前面的函數在原tuple後面追加數據不同,PartitionAggregate的輸出會直接替換掉輸入的tuple,僅數據PartitionAggregate中發射的tuple。栗子,定義一個累加的PartitionAggregate:

stream.partitionAggregate(new Fields(“b”), new Sum(), new Fields(“sum”));

上面語句完成對partition內數據進行分組累加的操作。

TridentAPI提供了三個聚合器的接口:CombinerAggregator, ReducerAggregator, and Aggregator.

1.5. Aggragation聚合操作
Trident有aggregate和 persistentAggregate方法來做聚合操作。aggregate是獨立的運行在Stream的每個Batch上的,而persistentAggregate則是運行在Stream的所有Batch上並把運算結果存儲在state source中。 運行aggregate方法做全局聚合。當你用到 ReducerAggregator或Aggregator時,Stream首先被重定向到一個分區中,然後其中的聚合函數便在這個分區上運行。當你用到CombinerAggregator時,Trident會首先在每個分區上做局部聚合,然後把局部聚合後的結果重定向到一個分區,因此使用CombinerAggregator會更高效,可能的話我們需要優先考慮使用它。 下面舉個例子來說明如何用aggregate進行全局計數:
stream.aggregate(new Count(), new Fields(“count”));
和paritionAggregate一樣,aggregators的聚合也可以串聯起來,但是如果你把一個 CombinerAggregator和一個非CombinerAggregator串聯在一起,Trident是無法完成局部聚合優化的。

1.6. grouped streams

GroupBy操作是根據特定的字段對流進行重定向的,還有,在一個分區內部,每個相同字段的tuple也會被Group到一起。 如果你在grouped Stream上面運行aggregators,聚合操作會運行在每個Group中而不是整個Batch。persistentAggregate也能運行在GroupedSteam上,不過結果會被保存在MapState中,其中的key便是分組的字段。 當然,aggregators在GroupedStreams上也可以串聯。
1.7. Merge和Joins:
api的最後一部分便是如何把各種流匯聚到一起。最簡單的方式就是把這些流匯聚成一個流。我們可以這麼做:
topology.merge(stream1, stream2, stream3);
另一種合併流的方式就是join。一個標準的join就像是一個sql,必須有標準的輸入,因此,join只針對符合條件的Stream。join應用在來自Spout的每一個小Batch中。join時候的tuple會包含:

  1. join的字段,如Stream1中的key和Stream2中的x
  2. 所有非join的字段,根據傳入join方法的順序,a和b分別代表steam1的val1和val2,c代表Stream2的val1
    當join的是來源於不同Spout的stream時,這些Spout在發射數據時需要同步,一個Batch所包含的tuple會來自各個Spout。
  3. 什麼是Storm Trident ?

Trident是編寫Storm Topology的一套高級框架,是對傳統Spout、Bolt的高級封裝。在學習Trident之前,我們都是都Spout、Bolt的相關API來編寫一個Topology,在學習了Trident之後,我們會使用Trident API來編寫Topology。

可以將StormTopology與TridentTopology的關係,類比爲JDBC與ORM框架(mybatis、hibernate)之間的關係,後者是前者的高級封裝,功能相同,但是可以極大的減少開發的工作量。
通常情況下,新的概念意味着要使用新的API。但是歸根結底,還是底層還是通過storm原語來實現。在Trident中,我們使用TridentTopology表示一個拓撲,而在Storm原語中,我們使用StormTopology來表示一個拓撲。TridentTopology最終會被轉換成StormTopology。

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