Component包含Executor(threads)的个数
在StormBase中的num-executors, 这对应于你写topology代码时, 为每个component指定的并发数(通过setBolt和setSpout)

 

Component和Task的对应关系, (storm-task-info)
默认你可以不指定task数, 那么task和executor为1:1关系
当然也可以通过ComponentConfigurationDeclarer#setNumTasks()去设置TOPOLOGY_TASKS
这个函数, 首先读出所有components
对每个component, 读出ComponentComm中的json_conf, 然后从里面读出上面设置的TOPOLOGY_TASKS
最后用递增序列产生taskid, 并最终生成component和task的对应关系
如果不设置, task数等于executor数, 后面分配就很容易, 否则就涉及task分配问题

  1. (defn storm-task-info
  2. "Returns map from task -> component id"
  3. [^StormTopology user-topology storm-conf]
  4. (->> (system-topology! storm-conf user-topology)
  5. all-components
  6. (map-val (comp #(get % TOPOLOGY-TASKS) component-conf))
  7. (sort-by first)
  8. (mapcat (fn [[c num-tasks]] (repeat num-tasks c)))
  9. (map (fn [id comp] [id comp]) (iterate (comp int inc) (int 1)))
  10. (into {})
  11. ))

首先产生system-topology!, 因为system-topology!会增加系统components, acker, systemBolt, metricsBlot, 这些也都是topology中不可缺少的部分, 所以单纯使用用户定义的topology是不够的

然后取出topology里面所有component

  1. (defn all-components [^StormTopology topology]
  2. (apply merge {}
  3. (for [f thrift/STORM-TOPOLOGY-FIELDS]
  4. (.getFieldValue topology f)
  5. )))

使用thrift/STORM-TOPOLOGY-FIELDS从StormTopology的metadata里面读出每个fieldid, 并取出value进行merge

所以结果就是下面3个map, merge在一起的集合

  1. struct StormTopology {
  2. //ids must be unique across maps
  3. // #workers to use is in conf
  4. 1: required map<string, SpoutSpec> spouts;
  5. 2: required map<string, Bolt> bolts;
  6. 3: required map<string, StateSpoutSpec> state_spouts;
  7. }

使用map-value对map中的component进行如下操作

取出component里面的ComponentComm对象(.getcommon), 并读出json_conf, 最终读出conf中TOPOLOGY-TASKS

  1. (defn component-conf [component]
  2. (->> component
  3. .get_common
  4. .get_json_conf
  5. from-json))
  1. struct ComponentCommon {
  2. 1: required map<GlobalStreamId, Grouping> inputs;
  3. 2: required map<string, StreamInfo> streams; //key is stream id
  4. 3: optional i32 parallelism_hint; //how many threads across the cluster should be dedicated to this component
  5. // component specific configuration
  6. 4: optional string json_conf;
  7. }

输出{component-string:tasknum}, 按component-string排序, 再进行mapcat

{c1 3, c2 2, c3 1} –> (c1,c1,c1,c2,c2,c3)

再加上递增编号, into到map, {1 c1, 2 c1, 3 c1, 4 c2, 5 c2, 6 c3}

Topology中, Task和Executor的分配关系, (compute-executors)

上面已经产生, component->executors 和 component->task, 现在根据component对应的task和executor个数进行task分配(到executor)

默认是1:1分配, 但如果设置了task数,

比如对于c1, 2个executor, 3个tasks [1 2 3], 分配结果就是['(1 2) ‘(3)]

最终to-executor-id, 列出每个executor中task id的范围([(first task-ids) (last task-ids)])

  1. (defn- compute-executors [nimbus storm-id]
  2. (let [conf (:conf nimbus)
  3. storm-base (.storm-base (:storm-cluster-state nimbus) storm-id nil)
  4. component->executors (:component->executors storm-base) ;从storm-base中获取每个component配置的(executor)线程数
  5. storm-conf (read-storm-conf conf storm-id)
  6. topology (read-storm-topology conf storm-id)
  7. task->component (storm-task-info topology storm-conf)]
  8. (->> (storm-task-info topology storm-conf)
  9. reverse-map ;{“c1 [1,2,3], c2 [4,5], c3 6}
  10. (map-val sort)
  11. (join-maps component->executors) ; {"c1" ‘(2 [1 2 3]), "c2" ‘(2 [4 5]), "c3" ‘(1 6)}
  12. (map-val (partial apply partition-fixed)) ; {"c1" ['(1 2) '(3)], "c2" ['(4) '(5)], "c3" ['(6)]}
  13. (mapcat second) ;((1 2) (3) (4) (5) (6))
  14. (map to-executor-id) ;([1 2] [3 3] [4 4] [5 5] [6 6])
  15. )))

 

partition-fixed, 将aseq分成max-num-chunks份

思路,

7整除3, 2余1

所以, 分成3份, 每份2个, 还余一个

把这个放到第一份里面,

所以, 有1份的2+1个, 有(3-1)份的2个

这里使用integer-divided(7 3), ([3 1] [2 2]) , 刚开始比较难理解, 其实函数名起的不好, 这里不光除, 已经做了划分

返回的结果的意思是, 1份3个, 2份2个

接着就是使用split-at, loop划分

  1. (defn partition-fixed
  2. “(partition-fixed 3 '( 1 2 3 4 5 6 7)) [(1 2 3) (4 5) (6 7)]”
  3. [max-num-chunks aseq]
  4. (if (zero? max-num-chunks)
  5. []
  6. (let [chunks (->> (integer-divided (count aseq) max-num-chunks)
  7. (#(dissoc % 0))
  8. (sort-by (comp - first))
  9. (mapcat (fn [[size amt]] (repeat amt size)))
  10. )]
  11. (loop [result []
  12. [chunk & rest-chunks] chunks
  13. data aseq]
  14. (if (nil? chunk)
  15. result
  16. (let [[c rest-data] (split-at chunk data)]
  17. (recur (conj result c)
  18. rest-chunks
  19. rest-data)))))))

 

Topology中, Executor和component的关系, (compute-executor->component ), 根据(executor:task)关系和(task:component)关系join

  1. (defn- compute-executor->component [nimbus storm-id]
  2. (let [conf (:conf nimbus)
  3. executors (compute-executors nimbus storm-id)
  4. topology (read-storm-topology conf storm-id)
  5. storm-conf (read-storm-conf conf storm-id)
  6. task->component (storm-task-info topology storm-conf)
  7. executor->component (into {} (for [executor executors
  8. :let [start-task (first executor)
  9. component (task->component start-task)]]
  10. {executor component}))]
  11. executor->component)) ;{[1 2] c1”, [3 3] c1”, [4 4] c2”, [5 5] c2”, [6 6] c3”}
  1.  

最终目的就是获得executor->component关系, 用于后面的assignment, 其中每个executor包含task范围[starttask, endtask]

 

 

Storm-源码分析- Component ,Executor ,Task之间关系的更多相关文章

  1. storm源码分析之任务分配--task assignment

    在"storm源码分析之topology提交过程"一文最后,submitTopologyWithOpts函数调用了mk-assignments函数.该函数的主要功能就是进行topo ...

  2. Storm源码分析--Nimbus-data

    nimbus-datastorm-core/backtype/storm/nimbus.clj (defn nimbus-data [conf inimbus] (let [forced-schedu ...

  3. JStorm与Storm源码分析(二)--任务分配,assignment

    mk-assignments主要功能就是产生Executor与节点+端口的对应关系,将Executor分配到某个节点的某个端口上,以及进行相应的调度处理.代码注释如下: ;;参数nimbus为nimb ...

  4. JStorm与Storm源码分析(四)--均衡调度器,EvenScheduler

    EvenScheduler同DefaultScheduler一样,同样实现了IScheduler接口, 由下面代码可以看出: (ns backtype.storm.scheduler.EvenSche ...

  5. JStorm与Storm源码分析(三)--Scheduler,调度器

    Scheduler作为Storm的调度器,负责为Topology分配可用资源. Storm提供了IScheduler接口,用户可以通过实现该接口来自定义Scheduler. 其定义如下: public ...

  6. Spark源码分析之八:Task运行(二)

    在<Spark源码分析之七:Task运行(一)>一文中,我们详细叙述了Task运行的整体流程,最终Task被传输到Executor上,启动一个对应的TaskRunner线程,并且在线程池中 ...

  7. Spark源码分析之七:Task运行(一)

    在Task调度相关的两篇文章<Spark源码分析之五:Task调度(一)>与<Spark源码分析之六:Task调度(二)>中,我们大致了解了Task调度相关的主要逻辑,并且在T ...

  8. Spark源码分析之六:Task调度(二)

    话说在<Spark源码分析之五:Task调度(一)>一文中,我们对Task调度分析到了DriverEndpoint的makeOffers()方法.这个方法针对接收到的ReviveOffer ...

  9. JStorm与Storm源码分析(一)--nimbus-data

    Nimbus里定义了一些共享数据结构,比如nimbus-data. nimbus-data结构里定义了很多公用的数据,请看下面代码: (defn nimbus-data [conf inimbus] ...

随机推荐

  1. Makefile 8——使用依赖关系文件

    Makefile中存在一个include指令,它的作用如同C语言中的#include预处理指令.在Makefile中,可以通过include指令将自动生成的依赖关系文件包含进来,从而使得依赖关系文件中 ...

  2. Eclipse中复制android项目后要改动的地方

    1.清单文件中,改package=2.修改包名3.清单文件中app_name F3点进去修改名字

  3. redhat6.8服务器版本 yum 源的配置

    阿里云的源地址: http://mirrors.aliyun.com/ 打开后点击帮助: 有如下提示: 不过不能直接使用这个源,因为自己使用的是服务器版本,要修改一个变量,先将源文件下载下来. wge ...

  4. 1.thinkphp 权限分析

    一.权限分析 用户表 user角色表 role权限表 node think_acces role_id 用户组idnode_id 节点IDlevel 节点等级pid 父级ID THINK_ACCESS ...

  5. 绝对详细!Nginx基本配置、性能优化指南

    大多数的Nginx安装指南告诉你如下基础知识——通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了!而且,在大多数情况下,一个常规安装的nginx对你的网站来说已经能 ...

  6. SSIS 自测题-文件操作类

    说明:以下是自己的理解答案,不是标准的答案,如有不妥烦请指出.         有些题目暂时没有答案,有知道的请留言,互相学习,一起进步. 1.什么是控制流,什么是数据流,控制流和数据流之间的关系是什 ...

  7. 阿里云ecs开启x11图形化桌面

    阿里云帮助文档:https://www.alibabacloud.com/help/zh/faq-detail/41227.htm 安装云服务器 ECS CentOS 7 图形化桌面 以安装 MATE ...

  8. printf 字体颜色打印

    为了给printf着色方便, 我们可以定义一些宏: view plain copy to clipboard print ? #define NONE          "/033[m&qu ...

  9. CAEmitterCell 和 CAEmitterLayer具体解释

    一.在 UIKit 中,粒子系统由两部分组成: 1·      一个或多个  CAEmitterCells :发射器电池能够看作是单个粒子的原型(比如,一个单一的粉扑在一团烟雾).当散发出一个粒子,U ...

  10. hdu 1147:Pick-up sticks(基本题,判断两线段相交)

    Pick-up sticks Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...