一、概述

     Storm Trident中的核心数据模型就是“Stream”,也就是说,Storm Trident处理的是Stream。可是实际上Stream是被成批处理的。Stream被切分成一个个的Batch分布到集群中,全部应用在Stream上的函数终于会应用到每一个节点的Batch中。实现并行计算。详细例如以下图所看到的:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VpZmVuZzMwNTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

在Trident中有五种操作类型:
  1. Apply Locally:本地操作,全部操作应用在本地节点数据上,不会产生网络传输
  2. Repartitioning:数据流重定向,单纯的改变数据流向。不会改变数据内容,这部分会有网络传输
  3. Aggragation:聚合操作,会有网络传输
  4. Grouped streams上的操作
  5. Merge和Join
小结:上面提到了Trident实际上是通过把函数应用到每一个节点的Batch上的数据以实现并行,而应用的这些函数就是TridentAPI,以下我们就详细介绍一下TridentAPI的各种操作。  

二、Trident五种操作具体解释


2.1 Apply Locally本地操作:操作都应用在本地节点的Batch上,不会产生网络传输


2.1.1 Functions:函数操作


     函数的作用是接收一个tuple(需指定接收tuple的哪个字段),输出0个或多个tuples。

输出的新字段值会被追加到原始输入tuple的后面,假设一个function不输出tuple,那就意味这这个tuple被过滤掉了,以下举例说明:

  • 定义一个Function:
  1. public class MyFunction extends BaseFunction {
  2. @Override
  3. public void execute(TridentTuple tuple, TridentCollector collector) {
  4. for ( int i = 0; i < tuple.getInteger(0); i++) {
  5. collector.emit( new Values(i));
  6. }
  7. }
  8. }
     小结:Function实际上就是对经过Function函的tuple做一些操作以改变其内容。
  • 比方我们处理一个“mystream”的数据流,它有三个字段各自是[“a”, “b”, “c”] ,数据流中tuple的内容是:
     [1,
2, 3] [4, 1, 6] [3, 0, 8]
  • 我们执行我们的Function:
  1. java mystream.each(new Fields("b"), new MyFunction(), new Fields("d")));
     它意思是接收输入的每一个tuple “b”字段得值。把函数结算结果做为新字段“d”追加到每一个tuple后面。然后发射出去。
  • 终于执行结果会是每一个tuple有四个字段[“a”, “b”, “c”, “d”]。每一个tuple的内容变成了:
     [1,
2, 3, 0] [1, 2, 3, 1] [4, 1, 6, 0]
    小结:我们注意到,假设一个function发射多个tuple时。每一个发射的新tuple中仍会保留原来老tuple的数据。



2.1.2 Filters:过滤操作
  • Filters非常easy,接收一个tuple并决定是否保留这个tuple。

    举个样例,定义一个Filter:

  1. public class MyFilter extends BaseFilter {
  2. public boolean isKeep(TridentTuple tuple) {
  3. return tuple.getInteger(0) == 1 && tuple.getInteger(1) == 2;
  4. }
  5. }
  • 如果我们的tuples有这个几个字段 [“a”,
    “b”, “c”]:
     [1, 2, 3] [2, 1, 1] [2, 3, 4]
  • 然后执行我们的Filter:
  1. java mystream.each(new Fields("b", "a"), new MyFilter())。
  • 则终于得到的tuple是 :
     [2,
1, 1]

     说明第一个和第三个不满足条件,都被过滤掉了。


     小结:Filter就是一个过滤器,它决定是否须要保留当前tuple。


2.1.3 PartitionAggregate
    PartitionAggregate的作用对每一个Partition中的tuple进行聚合。与前面的函数在原tuple后面追加数据不同,PartitionAggregate的输出会直接替换掉输入的tuple。仅数据PartitionAggregate中发射的tuple。以下举例说明:
  • 定义一个累加的PartitionAggregate:
  1. java mystream.partitionAggregate(new Fields("b"), new Sum(), new Fields("sum"));
  • 如果我们的Stream包括两个字段 [“a”,
    “b”],各个Partition的tuple内容是:
     ```
Partition 0: [“a”, 1] [“b”, 2]

Partition 1: [“a”, 3] [“c”, 8]

     Partition 2: [“e”, 1] [“d”, 9] [“d”, 10] ```
  • 输出的内容仅仅有一个字段“sum”,值是:
     ```
Partition 0: [3]

Partition 1: [11]

     Partition 2: [20] ```

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


我们先看一下CombinerAggregator接口:   
  1. public interface CombinerAggregator <T> extends Serializable {
  2. T init(TridentTuple tuple);
  3. T combine(T val1, T val2);
  4. T zero();
  5. }
    CombinerAggregator接口仅仅返回一个tuple,而且这个tuple也仅仅包括一个field。init方法会先运行。它负责预处理每个接收到的tuple。然后再运行combine函数来计算收到的tuples直到最后一个tuple到达。当全部tuple处理完时,CombinerAggregator会发射zero函数的输出,举个样例:
  • 定义一个CombinerAggregator实现来计数:
  1. public class CombinerCount implements CombinerAggregator<Integer>{
  2. @Override
  3. public Integer init(TridentTuple tuple) {
  4. return 1;
  5. }
  6. @Override
  7. public Integer combine(Integer val1, Integer val2) {
  8.  
  9. return val1 + val2;
  10. }
  11. @Override
  12. public Integer zero() {
  13. return 0;
  14. }
  15. }
     小结:当你使用aggregate 方法取代PartitionAggregate时。CombinerAggregator的优点就体现出来了,由于Trident会自己主动优化计算,在网络传输tuples之前做局部聚合。

我们再看一下ReducerAggregator:
  1. public interface ReducerAggregator <T> extends Serializable {
  2. T init();
  3. T reduce(T curr, TridentTuple tuple);
  4. }
     ReducerAggregator通过init方法提供一个初始值,然后为每一个输入的tuple迭代这个值,最后生产处一个唯一的tuple输出,以下举例说明:
  • 定义一个ReducerAggregator接口实现技术器的样例:
  1. public class ReducerCount implements ReducerAggregator<Long>{
  2. @Override
  3. public Long init() {
  4. return 0L;
  5. }
  6. @Override
  7. public Long reduce(Long curr, TridentTuple tuple) {
  8. return curr + 1;
  9. }
  10. }
  1. 最后一个是Aggregator接口,它是最通用的聚合器,它的形式例如以下:
  1.   public interface Aggregator<T> extends Operation {
  2.         T init(Object batchId, TridentCollector collector);
  3.         void aggregate(T val, TridentTuple tuple, TridentCollector collector);
  4.         void complete(T val, TridentCollector collector);
  5.    }
    Aggregator接口能够发射含随意数量属性的随意数据量的tuples,而且能够在运行过程中的不论什么时候发射:
  1. init:在处理数据之前被调用,它的返回值会作为一个状态值传递给aggregate和complete方法
  2. aggregate:用来处理每个输入的tuple,它能够更新状态值也能够发射tuple
  3. complete:当全部tuple都被处理完毕后被调用
  1. 以下举例说明:
  • 定义一个实现来完毕一个计数器:
  1.    public class CountAgg extends BaseAggregator<CountState>{
  2.      static class CountState { long count = 0; }
  3.      @Override
  4.      public CountState init(Object batchId, TridentCollector collector) {
  5.            return new CountState();
  6.      }
  7.      @Override
  8.      public void aggregate(CountState val, TridentTuple tuple, TridentCollector collector) {
  9.           val. count+=1;
  10.      }
  11.      @Override
  12.      public void complete(CountState val, TridentCollector collector) {
  13.           collector.emit( new Values(val. count));
  14.      }
  15.   }
  1. 有时候我们须要同一时候运行多个聚合器。这在Trident中被称作chaining,用法例如以下:
  1. java mystream.chainedAgg() .partitionAggregate(new Count(), new Fields("count")) .partitionAggregate(new Fields("b"), new Sum(), new Fields("sum")) .chainEnd();
  1. 这点代码会在每一个Partition上执行countsum函数,终于输出一个tuple:[“count”, sum”]
  1. projection:投影操作
  1. 投影操作作用是仅保留Stream指定字段的数据,比方有一个Stream包括例如以下字段: [“a”, b”, c”, d”]
  1. 执行例如以下代码:
  1. java mystream.project(new Fields("b", "d"))
  1. 则输出的流仅包括 [“b”, d”]字段。
  1. 2.2 Repartitioning重定向操作
  1. 重定向操作是怎样在各个任务间对tuples进行分区。分区的数量也有可能改变重定向的结果。
  2.  
  3. 重定向须要网络传输,以下介绍下重定向函数:
  1. shuffle:通过随机分配算法来均衡tuple到各个分区
  2. broadcast:每一个tuple都被广播到全部的分区。这样的方式在drcp时很实用。比方在每一个分区上做stateQuery
  3. partitionBy:依据指定的字段列表进行划分,详细做法是用指定字段列表的hash值对分区个数做取模运算,确保同样字段列表的数据被划分到同一个分区
  4. global:全部的tuple都被发送到一个分区,这个分区用来处理整个Stream
  5. batchGlobal:一个Batch中的全部tuple都被发送到同一个分区,不同的Batch会去往不同的分区
  6. Partition:通过一个自己定义的分区函数来进行分区,这个自己定义函数实现了 backtype.storm.grouping.CustomStreamGrouping
2.3 Aggragation聚合操作
  1. Tridentaggregate persistentAggregate方法来做聚合操作。aggregate是独立的执行在Stream的每一个Batch上的,而persistentAggregate则是执行在Stream的全部Batch上并把运算结果存储在state source中。
  2. 执行aggregate方法做全局聚合。
  3.  
  4. 当你用到 ReducerAggregatorAggregator时,Stream首先被重定向到一个分区中。然后当中的聚合函数便在这个分区上执行。当你用到CombinerAggregator时,Trident会首先在每一个分区上做局部聚合。然后把局部聚合后的结果重定向到一个分区。因此使用CombinerAggregator会更高效。可能的话我们须要优先考虑使用它。
  5. 以下举个样例来说明怎样用aggregate进行全局计数:
  6. java mystream.aggregate(new Count(), new Fields("count"));
  7. paritionAggregate一样,aggregators的聚合也能够串联起来。可是假设你把一个 CombinerAggregator和一个非CombinerAggregator串联在一起,Trident是无法完毕局部聚合优化的。

  1. 2.4 grouped streams
  1. GroupBy操作是依据特定的字段对流进行重定向的,还有,在一个分区内部,每一个同样字段的tuple也会被Group到一起,以下这幅图描写叙述了这个场景:
  1. 假设你在grouped Stream上面执行aggregators,聚合操作会执行在每一个Group中而不是整个Batch
  2.  
  3. persistentAggregate也能执行在GroupedSteam上,只是结果会被保存在MapState中。当中的key便是分组的字段。
  4.  
  5. 当然。aggregatorsGroupedStreams上也能够串联。
  1. 2.5 MergeJoins:
  1. api的最后一部分便是怎样把各种流汇聚到一起。最简单的方式就是把这些流汇聚成一个流。我们能够这么做:
  2. java topology.merge(stream1, stream2, stream3);
  3. 还有一种合并流的方式就是join

  4. 一个标准的join就像是一个sql,必须有标准的输入,因此,join仅仅针对符合条件的Stream

  5. join应用在来自Spout的每个小Batch中。join时候的tuple会包括:  

  1. 1. join的字段,如Stream1中的keyStream2中的x  
  1. 2. 全部非join的字段,依据传入join方法的顺序,ab分别代表steam1val1val2c代表Stream2val1  
  1. join的是来源于不同Spoutstream时。这些Spout在发射数据时须要同步,一个Batch所包括的tuple会来自各个Spout
  1.  
  1.  
  1. 关于Trident State 相关内容请參考Trident State具体解释】
  1. 关于TridentAPI实践方面,请參考Trident API实践】
  1.  

Storm专题二:Storm Trident API 使用具体解释的更多相关文章

  1. Storm系列二: Storm拓扑设计

    Storm系列二: Storm拓扑设计 在本篇中,我们就来根据一个案例,看看如何去设计一个拓扑, 如何分解问题以适应Storm架构,同时对Storm拓扑内部的并行机制会有一个基本的了解. 本章代码都在 ...

  2. Storm(二)CentOS7.5搭建Storm1.2.2集群

    一.Storm的下载 官网下载地址:http://storm.apache.org/downloads.html 这里下载最新的版本storm1.2.2,进入之后选择一个镜像下载 二.Storm伪分布 ...

  3. Storm介绍(二)

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文是Storm系列之一,主要介绍Storm的架构设计,推荐读者在阅读 ...

  4. Storm简介——初始Storm

    一.什么是Storm Strom是由Twitter开源的类似于Hadoop的实时数据处理框架.Strom是分布式流式数据处理系统,强大的分布式集群管理.便捷的针对流式数据的编程模型.高容错保障这些都是 ...

  5. 1 storm基本概念 + storm编程规范及demo编写

    本博文的主要内容有 .Storm的单机模式安装 .Storm的分布式安装(3节点)   .No space left on device .storm工程的eclipse的java编写 http:// ...

  6. Storm 01之 Storm基本概念及第一个demo

    2.1 Storm基本概念 在运行一个Storm任务之前,需要了解一些概念: Topologies :[tə'pɑ:lədʒɪ]拓扑结构 Streams Spouts:[spaʊt]喷出; 喷射; 滔 ...

  7. 百度网盘生成二维码api

    分享出自精神,灵感来自大脑,在百度云网盘分享每一个文件,都会在页面生成一个二维码扫描的图片: 我就进一步看了该图片的地址: 发现没有,圈圈内是不是有点眼熟,就跟其他二维码api接口一样,只要盗用这段东 ...

  8. 实时数据处理环境搭建flume+kafka+storm:4.storm安装配置

    1.解压 apache-storm-0.9.3.tar.gz   2.修改配置文件 conf/storm.yaml --zk地址  storm.zookeeper.servers:  - " ...

  9. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

随机推荐

  1. Must set property 'expression' before attempting to match

    因为这个问题没有直接指向问题的地点, 所以找起来不是很容易. 但是如果找不到, 这个错就会一直都存在. 原因分析: 在使用切面编程的时候, 没有把切入点配置全面 解决方法: 在before, afte ...

  2. Perl语言入门: 斜线不是元字符,所以在不作为分隔符时不需要加上反斜线。

    Perl语言入门: 斜线不是元字符,所以在不作为分隔符时不需要加上反斜线.

  3. 详解Spring面向切面编程(AOP)三种实现

    一.什么是AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善. ...

  4. python读取excel学习(1)

    #coding=gbk #coding=utf-8 import xlrd table = xlrd.open_workbook(r'E:\test.xlsx') #sheet = table.she ...

  5. tornado框架基础07-sqlalchemy查询

    01 查询结果 上节使用query从数据库中查询到了结果,但是query返回的对象是直接可用的吗? 首先导入模块 from connect import session from user_modul ...

  6. LeetCode(31) Next Permutation

    题目 Implement next permutation, which rearranges numbers into the lexicographically next greater perm ...

  7. 《算法导论》 — Chapter 7 快速排序

    序 快速排序(QuickSort)也是一种排序算法,对包含n个数组的输入数组,最坏情况运行时间为O(n^2).虽然这个最坏情况运行时间比较差,但是快速排序通常是用于排序的最佳实用选择,这是因为其平均性 ...

  8. 根据不同的产品id获得不同的下拉选项 (option传多值)

    <td> 没有 value 所以要在<td>里面加上input  同时text 为hidden这样就不会显示value的值 <td><select id='g ...

  9. IntrospectorCleanupListener监听器防止内存溢出

    <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</ ...

  10. Java学习之理解递归

    Java支持递归.递归是根据自身定义内容的过程.就Java编程而言,递归是一个允许方法调用自身的特性.调用自身的方法被称为递归.典型的例子就是阶乘的计算,N的阶乘就是从1到N之间所有整数的乘积. 当方 ...