1. GeneralTopologyContext

记录了Topology的基本信息, 包含StormTopology, StormConf
已经从他们推导出的, task和component, component的streams, input/output信息

public class GeneralTopologyContext implements JSONAware {
private StormTopology _topology;
private Map<Integer, String> _taskToComponent;
private Map<String, List<Integer>> _componentToTasks;
private Map<String, Map<String, Fields>> _componentToStreamToFields; //ComponentCommon.streams, map<string, StreamInfo>
private String _stormId; ;;topology id
protected Map _stormConf; }

StormTopology, worker从磁盘stormcode.ser中读出

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

StormConf, worker从磁盘stormconf.ser中读出

taskToComponent, componentToTasks, task和component的对应关系

componentToStreamToFields, component包含哪些streams, 每个stream包含哪些fields

除了显而易见的操作以外, 还有如下操作以获得component的输入和输出

    /**
* Gets the declared inputs to the specified component.
*
* @return A map from subscribed component/stream to the grouping subscribed with.
*/
public Map<GlobalStreamId, Grouping> getSources(String componentId) {
return getComponentCommon(componentId).get_inputs(); //ComponentCommon.inputs,map<GlobalStreamId, Grouping>
}
    /**
* Gets information about who is consuming the outputs of the specified component,
* and how.
*
* @return Map from stream id to component id to the Grouping used.
*/
public Map<String, Map<String, Grouping>> getTargets(String componentId) {
Map<String, Map<String, Grouping>> ret = new HashMap<String, Map<String, Grouping>>();
for(String otherComponentId: getComponentIds()) { //对所有components的id
Map<GlobalStreamId, Grouping> inputs = getComponentCommon(otherComponentId).get_inputs(); //取出component的inputs
for(GlobalStreamId id: inputs.keySet()) { //对inputs里面的每个stream-id
if(id.get_componentId().equals(componentId)) { //判断stream的源component是否是该component
Map<String, Grouping> curr = ret.get(id.get_streamId());
if(curr==null) curr = new HashMap<String, Grouping>();
curr.put(otherComponentId, inputs.get(id));
ret.put(id.get_streamId(), curr);
}
}
}
return ret; // [steamid, [target-componentid, grouping]]
}

这里面的getComponentCommon和getComponentIds, 来自ThriftTopologyUtils类

不要误解, 不是通过thriftAPI去nimbus获取信息, 只是从StormTopology里面读信息, 而StormTopology类本身是generated by thrift

thrift产生的class, 是有metaDataMap的, 所以实现如下

    public static Set<String> getComponentIds(StormTopology topology) {
Set<String> ret = new HashSet<String>();
for(StormTopology._Fields f: StormTopology.metaDataMap.keySet()) {
Map<String, Object> componentMap = (Map<String, Object>) topology.getFieldValue(f);
ret.addAll(componentMap.keySet());
}
return ret;
}

通过metaDataMap读出StormTopology里面有哪些field, spouts,bolts,state_spouts, 然后遍历getFieldValue, 将value中的keyset返回

这样做的好处是, 动态, 当StormTopology发生变化时, 代码不用改, 对于普通java class应该无法实现这样的功能, 但是对于python这样的动态语言, 就简单了

当然这里其实也可以不用ThriftTopologyUtils, 直接写死从StormTopology.spouts…中去读

 

从storm.thrift里面看看ComponentCommon的定义, 上面两个函数就很好理解了

getTargets的实现, 需要看看, 因为是从inputs去推出outputs

因为在ComponentCommon只记录了output的streamid以及fields, 但无法知道这个stream发往哪个component

但对于input, streamid是GlobalStreamId类型, GlobalStreamId里面不但包含streamid,还有源component的componentid

所以从这个可以反推, 只要源component是当前component, 那么说明该component是源component的target component

struct ComponentCommon {
1: required map<GlobalStreamId, Grouping> inputs;
2: required map<string, StreamInfo> streams; //key is stream id, outputs
3: optional i32 parallelism_hint; //how many threads across the cluster should be dedicated to this component
4: optional string json_conf;
} struct SpoutSpec {
1: required ComponentObject spout_object;
2: required ComponentCommon common;
// can force a spout to be non-distributed by overriding the component configuration
// and setting TOPOLOGY_MAX_TASK_PARALLELISM to 1
} struct Bolt {
1: required ComponentObject bolt_object;
2: required ComponentCommon common;
}

 

2. WorkerTopologyContext

WorkerTopologyContext封装了些worker相关信息

public class WorkerTopologyContext extends GeneralTopologyContext {
public static final String SHARED_EXECUTOR = "executor"; private Integer _workerPort; ;;worker进程的port
private List<Integer> _workerTasks; ;;worker包含的taskids
private String _codeDir; ;;supervisor上的代码目录, stormdist/stormid
private String _pidDir; ;;记录worker运行进程(可能多个)的pids的目录,workid/pids
Map<String, Object> _userResources;
Map<String, Object> _defaultResources; }

 

3. TopologyContext

看注释, TopologyContext会作为bolt和spout的prepare(or open)函数的参数

所以用openOrPrepareWasCalled, 表示该TopologyContext是否被prepare调用过

registerMetric, 可以用于往_registeredMetrics中注册metics

注册的结构, [timeBucketSizeInSecs, [taskId, [name, metric]]]

_hooks, 用于注册task hook

/**
* A TopologyContext is given to bolts and spouts in their "prepare" and "open"
* methods, respectively. This object provides information about the component's
* place within the topology, such as task ids, inputs and outputs, etc.
*
* <p>The TopologyContext is also used to declare ISubscribedState objects to
* synchronize state with StateSpouts this object is subscribed to.</p>
*/
public class TopologyContext extends WorkerTopologyContext implements IMetricsContext {
private Integer _taskId;
private Map<String, Object> _taskData = new HashMap<String, Object>();
private List<ITaskHook> _hooks = new ArrayList<ITaskHook>();
private Map<String, Object> _executorData;
private Map<Integer,Map<Integer, Map<String, IMetric>>> _registeredMetrics;
private clojure.lang.Atom _openOrPrepareWasCalled;
    public TopologyContext(StormTopology topology, Map stormConf,
Map<Integer, String> taskToComponent, Map<String, List<Integer>> componentToSortedTasks,
Map<String, Map<String, Fields>> componentToStreamToFields,
String stormId, String codeDir, String pidDir, Integer taskId,
Integer workerPort, List<Integer> workerTasks, Map<String, Object> defaultResources,
Map<String, Object> userResources, Map<String, Object> executorData, Map registeredMetrics,
clojure.lang.Atom openOrPrepareWasCalled) {
super(topology, stormConf, taskToComponent, componentToSortedTasks,
componentToStreamToFields, stormId, codeDir, pidDir,
workerPort, workerTasks, defaultResources, userResources);
_taskId = taskId;
_executorData = executorData;
_registeredMetrics = registeredMetrics;
_openOrPrepareWasCalled = openOrPrepareWasCalled;
}

 

4. 使用

mk-task-data, 创建每个task的topology context

user-context (user-topology-context (:worker executor-data) executor-data task-id)
(defn user-topology-context [worker executor-data tid]
((mk-topology-context-builder
worker
executor-data
(:topology worker))
tid)) (defn mk-topology-context-builder [worker executor-data topology]
(let [conf (:conf worker)]
#(TopologyContext.
topology
(:storm-conf worker)
(:task->component worker)
(:component->sorted-tasks worker)
(:component->stream->fields worker)
(:storm-id worker)
(supervisor-storm-resources-path
(supervisor-stormdist-root conf (:storm-id worker)))
(worker-pids-root conf (:worker-id worker))
(int %)
(:port worker)
(:task-ids worker)
(:default-shared-resources worker)
(:user-shared-resources worker)
(:shared-executor-data executor-data)
(:interval->task->metric-registry executor-data)
(:open-or-prepare-was-called? executor-data))))

Storm-源码分析-Topology Submit-Task-TopologyContext (backtype.storm.task)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. Nimbus<三>Storm源码分析--Nimbus启动过程

    Nimbus server, 首先从启动命令开始, 同样是使用storm命令"storm nimbus”来启动看下源码, 此处和上面client不同, jvmtype="-serv ...

  8. 【原】storm源码之mac os x编译twitter storm源码

    twitter storm是由backtype公司创始人nathanmarz一手研发和开源的流计算(实时计算)框架,堪称实时计算领域的hadoop.nathanmarz也是在mac os x环境下开发 ...

  9. storm源码分析之topology提交过程

    storm集群上运行的是一个个topology,一个topology是spouts和bolts组成的图.当我们开发完topology程序后将其打成jar包,然后在shell中执行storm jar x ...

  10. JStorm与Storm源码分析(五)--SpoutOutputCollector与代理模式

    本文主要是解析SpoutOutputCollector源码,顺便分析该类中所涉及的设计模式–代理模式. 首先介绍一下Spout输出收集器接口–ISpoutOutputCollector,该接口主要声明 ...

随机推荐

  1. cocos2d-x发生undefined reference to `XX'异常 一劳永逸解决办法

    cocos2d-x发生undefined reference to `XX'错误 一劳永逸解决方法 参考文章: http://blog.csdn.net/kafeidev/article/detail ...

  2. pre 标签的使用

    1.在 div为contenteditable = true 中: 换行显示:就使用了pre 标签: 避免了/n 和空格的转换:实现了ctrl + enter 换行:显示的问题: 2.如何超过了div ...

  3. 深入剖析 linux GCC 4.4 的 STL string

    转自: 深入剖析 linux GCC 4.4 的 STL string 本文通过研究STL源码来剖析C++中标准模板块库std::string运行机理,重点研究了其中的引用计数和Copy-On-Wri ...

  4. 删除CNNIC根证书

    操作方法: 1.点击IE工具菜单-->选项-->内容-->证书,在受信任的根证书颁发机构中找到CNNIC Root,将证书导出到桌面备用. 双击CNNIC ROOT查看这个证书的属性 ...

  5. [转]JavaScript放在<head>和<body>的区别

    原文:http://liminhappygirl.iteye.com/blog/1841360 javaScript放在<head>和<body>的区别: 在HTML body ...

  6. [基础]关于extern指针和数组的用法

    之前有在外面面试,遇到一题如下: filea.c char *p = "abcdefg"; fileb.c extern char p[]; printf(]); result=? ...

  7. 简单实现Spring中BeanFactory原理

    上一篇文章介绍了Java反射机制在Spring IOC中的应用,知道了BeanFactory底层的实现原理. 原理搞懂了,对Spring IOC理解起来也很容易. 先来看看Java代码获取Spring ...

  8. sama5d36 can0 can1 测试

    1 删除/bin/ip 保留/sbin/ip 2 ip link set can0 type can bitrate 125000 ip link set can1 type can bitrate ...

  9. BLUETOOTH:HCI层编程

    1. HCI层协议概述: Host Controller Interface(HCI)  就是用来沟通Host和Module.Host通常就是PC,Module则是以各种物理连接形式(USB,seri ...

  10. 一次完整的https过程

    参考: 1. 一次完整的HTTP事务是怎样一个过程? 2. The First Few Milliseconds of an HTTPS Connection 3. 也许,这样理解HTTPS更容易 4 ...