strom-tulpe补充(2)

2121SC@SDUSC

strom-tulpe补充(2)

tuple

tuple是一个类似于列表的东西,存储的每个元素叫做field(字段),可以是任何类型。
Storm使用tuple作为它的数据模型, 每个tuple是一堆值,每个值都有一个名字。
一个Tuple代表数据流中的一个基本处理单元,例如:一条cookie日志,他可以包含多个Field, 每个Field表示一个属性。
一个没有边界、源源不断的Tuple序列就组成了Stream。

topology里面的每个节点,必须定义它要发射的Tuple的每个字段,必须下面这个bolt定义它所发射的tuple包含两个字段,类型分别为double,triple。

public class DoubleAndTripleBolt implements IRichBolt {

private OutputCollector _collector;

@Override

public void prepare(Map conf, TopologyContext context, OutputCollector collector) {

    _collector = collector;

}

@Override

public voide xecute(Tuple input) {

    int val = input.getInteger(0);

    _collector.emit(input,new Values(val*2, val*3));

    _collector.ack(input);

}

@Override

public void cleanup() {

}

@Override

public void declareOutputFields(OutputFieldsDeclarer declarer) {

    declarer.declare(newFields("double","triple"));

}

}

// declareOutputFields方法定义要输出的字段 : [“double”, “triple”]。

nextTuple()

这是Spout类中最重要的一个方法。发射一个Tuple到Topology都是通过这个方法来实现的。调用此方法时,storm向spout发出请求, 让spout发出元组(tuple)到输出器(ouput collector)。这种方法应该是非阻塞的,所以spout如果没有元组发出,这个方法应该返回。nextTuple、ack 和fail 都在spout任务的同一个线程中被循环调用。 当没有元组的发射时,应该让nextTuple睡眠一个很短的时间(如一毫秒),以免浪费太多的CPU。

tuple的分发策略 grouping

从一个bolt中产生的tuple可以有多个bolt接收,其实在twitter storm中有两个层面的分发策略问题,一个是对于task level的,另一个就是针对tuple level的分发。

bolt-emit
 (let [out-tasks (if task
	    (tasks-fn task stream values)
	  (tasks-fn stream values))]
 (fast-list-iter [t out-tasks]
	  (let [anchors-to-ids (HashMap.)]
	    (fast-list-iter [^TupleImpl a anchors]
			    (let [root-ids (-> a .getMessageId .getAnchorsToIds .keySet)]
			      (when (pos? (count root-ids))
				(let [edge-id (MessageId/generateId rand)]
				  (.updateAckVal a edge-id)
				  (fast-list-iter [root-id root-ids]
						  (put-xor! anchors-to-ids root-id edge-id))
				  ))))
	    (transfer-fn t
			 (TupleImpl. worker-context
				     values
				     task-id
				     stream
				     (MessageId/makeId anchors-to-ids)))))

上述代码显示t从out-tasks来,而out-tasks是tasks-fn的返回值

tasks-fn (:tasks-fn task-data)
  • tasks-fn,原来从未涉及的文件task.clj这次被挂上了,task-data与由task/mk-task创建。将中间环节跳过,调用关系如下所列。

mk-task
mk-task-data
mk-tasks-fn
tasks-fn中会使用到grouping,处理代码如下

fn ([^Integer out-task-id ^String stream ^List values]
      (when debug?
        (log-message "Emitting direct: " out-task-id "; " component-id " " stream " " values))
      (let [target-component (.getComponentId worker-context out-task-id)
            component->grouping (get stream->component->grouper stream)
            grouping (get component->grouping target-component)
            out-task-id (if grouping out-task-id)]
        (when (and (not-nil? grouping) (not= :direct grouping))
          (throw (IllegalArgumentException. "Cannot emitDirect to a task expecting a regular grouping")))                          
        (apply-hooks user-context .emit (EmitInfo. values stream task-id [out-task-id]))
        (when (emit-sampler)
          (builtin-metrics/emitted-tuple! (:builtin-metrics task-data) executor-stats stream)
          (stats/emitted-tuple! executor-stats stream)
          (if out-task-id
            (stats/transferred-tuples! executor-stats stream 1)
            (builtin-metrics/transferred-tuple! (:builtin-metrics task-data) executor-stats stream 1)))
        (if out-task-id [out-task-id])
        ))

每个topology中的grouping策略是由另一端executor-data实现的。

在mk-executor-data中有下面一行代码

:stream->component->grouper (outbound-components worker-context component-id)


(defn outbound-components
 "Returns map of stream id to component id to grouper"
 [^WorkerTopologyContext worker-context component-id]
 (->> (.getTargets worker-context component-id)
   clojurify-structure
   (map (fn [[stream-id component->grouping]]
    [stream-id
     (outbound-groupings
      worker-context
      component-id
      stream-id
      (.getComponentOutputFields worker-context component-id stream-id)
      component->grouping)]))
   (into {})
   (HashMap.)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值