storm从入门到精通 第五节 Trident

trident是storm实时计算框架。主要功能是:完成大吞吐量的流式计算、状态维护、低延迟分布式查询。

流式分割计算

FixedBatchSpout spout = new FixedBatchSpout(new Fields("sentence"), 3,
               new Values("the cow jumped over the moon"),
               new Values("the man went to the store and bought some candy"),
               new Values("four score and seven years ago"),
               new Values("how many apples can you eat"));
spout.setCycle(true);
这个spout会循环输出列出的那些语句到sentence stream当中,下面的代码会以这个stream作为输入并计算每个单词的个数:
TridentTopology topology = new TridentTopology();
TridentState wordCounts =
     topology.newStream("spout1", spout)
       .each(new Fields("sentence"), new Split(), new Fields("word"))
       .groupBy(new Fields("word"))
       .persistentAggregate(new MemoryMapState.Factory(), new Count(), new Fields("count"))
       .parallelismHint(6);
上面代码主要可以解释为以下几步:
    1、TridentTopology从数据源spout中读取数据并创建新的流,命名为spout1
    2、Split函数读取输入流中的“sentence”字段并将其拆分成若干个word tuple(batch中的tuple可能会数千或数百万数量级)
    3、根据“word”字段分组;
    4、使用count聚合字段出现的次数,然后持久到内存中
    5、persistentAggregate方法把数据流转换成TridentState对象。在这个例子当中,TridentState对象代表了所有的单词的数量

低延迟分布式查询

topology.newDRPCStream("words")
       .each(new Fields("args"), new Split(), new Fields("word"))
       .groupBy(new Fields("word"))
       .stateQuery(wordCounts, new Fields("word"), new MapGet(), new Fields("count"))
       .each(new Fields("count"), new FilterNull())
       .aggregate(new Fields("count"), new Sum(), new Fields("sum"));




思考

    Storm通过保证每个tuple至少被处理一次来提供可靠的数据处理。既然所有的tuple都会被处理,那么就会存在一个问题,如果一个tuple处理失败,spout会重发。那么我们怎么在storm上面做统计个数之类的事情呢,数据可靠吗,storm有可能会重复计数吧。

trident是什么

    简单讲trident就是storm提供的一套接口,用来处理数据流。
    trident以批处理的方式处理tuple。
    Trident以一种容错的方式来管理状态以至于当你在更新状态的时候你不需要去考虑错误以及重试的情况

trident作用

    通过一个例子来说明trident的作用:
    假设在做一个stream计数聚合,把每次计数的结果存到数据库中,每次处理一个tuple,将数据库中的计数加1。
    当错误发生,truple会被重发。这就带来了一个问题:当状态更新的时候,你完全不知道你是不是在之前已经成功处理过这个tuple。也许你之前从来没处理过这个tuple,这样的话你就应该把count加一。另外一种可能就是你之前是成功处理过这个tuple的,但是这个在其他的步骤处理这个tuple的时候失败了,在这种情况下,我们就不应该将count加一。再或者,你接受到过这个tuple,但是上次处理这个tuple的时候在更新数据库的时候失败了,这种情况你就应该去更新数据库。
如果只是简单的存计数到数据库,你是完全不知道这个tuple之前是否已经被处理过了的。所以你需要更多的信息来做正确的决定。

spout的类型

transaction spouts

    Trident是以小批量的形式在处理tuple,并且每一批都会分配一个唯一的transaction id。 
        1、同样txid的batch一定是一样的。当重播一个txid对应的batch时,一定会重发和之前对应txid的batch中同样的tuples。
        2、各个batch之间是没有交集的。每个tuple只能属于一个batch
        3、每一个tuple都属于一个batch。
    并不是所有的地方都需要容错的。举例来说,TransactionalTridentKafkaSpout 工作的方式是给定一个txid的batch所包含的一个属于一个topic的来自于所有Kafka partition的tuple序列。一旦这个batch被发出,在任何时候如果这个batch被重新发出时,它必须包含原来所有的tuple以满足 transactional spout的语义。现在我们假定一个batch被TransactionalTridentKafkaSpout所发出,这个batch没有被成功处理,并且同时kafka的一个节点也down掉了。你就无法像之前一样重播一个完全一样的batch(因为kakfa的节点down掉,该topic的一部分partition可能会无法使用),整个处理会被中断。


这也就是"opaque transactional" spouts(不透明事务spout)存在的原因- 他们对于丢失源节点这种情况是容错的,仍然能够帮你达到有且只有一次处理的语义。后面会对这种spout有所介绍。


(当然,在Kafka开启replication功能时,transactional spout也是可以做到容错的)


在外面来讨论"opaque transactional" spout之前,我们先来看看你应该怎样设计一个State来实现transactional spout的有且只有一次执行的语义。这个State的类型是"transactional state" 并且它利用了任何一个txid总是对应同样的tuple序列这个语义。


假如说你有一个用来计算单词出现次数的topology,你想要将单词的出现次数以key/value对的形式存储到数据库中。key就是单词,value就是这个这个单词出现的次数。你已经看到只是存储一个数量是不足以知道你是否已经处理过一个batch的。你可以通过将value和txid一起存储到数据库中。这样的话,当更新这个count之前,你可以先去比较数据库中存储的txid和现在要存储的txid。如果一样,就跳过什么都不做,因为这个value之前已经被处理过了。如果不一样,就执行存储。这个逻辑可以工作的前提就是txid永不改变,并且Trident保证状态的更新是在batch之间严格顺序进行的。


考虑下面这个例子的运行逻辑, 假定你在处理一个txid为3的包含下面tuple的batch:



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值