Topology、Spout、Blot生命周期

转载自:
https://blog.youkuaiyun.com/dslztx/article/details/46687833
https://blog.youkuaiyun.com/dslztx/article/details/46691841
https://blog.youkuaiyun.com/weijonathan/article/details/18792719

Topology

  "storm jar"命令用于启动一个Topology。storm jar设置的环境变量会提供给StormSubmiiter后续使用。在代码中调用StormSubmitter#submitTopology或者StormSubmitter#submitTopologyWithProgressBar时,最终都会调用StormSubmitter#submitTopologyAs
 在submitTopologyAs方法中,首先是加载配置:

if(!Utils.isValidConf(stormConf)) {
    throw new IllegalArgumentException("Storm conf is not valid. Must be json-serializable");
}
stormConf = new HashMap(stormConf);
stormConf.putAll(Utils.readCommandLineOpts());
Map conf = Utils.readStormConfig();
conf.putAll(stormConf);
stormConf.putAll(prepareZookeeperAuthentication(conf));

validateConfs(conf, topology);

  先检查拓扑传进来的stormConf是否有效,能否json化,然后将其转换为HashMap,这里的stormConf是用户在建立拓扑创建的;然后将命令行中的参数加载进stormConf中;
  调用readStormConfig,加载配置文件中的内容,先加载defaults.yaml, 然后再加载storm.yaml,并合并stormConf中的配置到conf中;
  最后,加载zk认证相关信息,并校验配置项。

  当配置准备好以后,就开始向nimbus提交拓扑。在storm中,nimbus是一个thrift服务器,它接受客户端通过json文件提交RPC调用,即NimbusClient向nimbus提供一份json格式的字符串,用于提交拓扑信息。

String serConf = JSONValue.toJSONString(stormConf);
try (NimbusClient client = NimbusClient.getConfiguredClientAs(conf, asUser)) {
    if (topologyNameExists(name, client)) {
        throw new RuntimeException("Topology with name `" + name + "` already exists on cluster");
    }

    // Dependency uploading only makes sense for distributed mode
    List<String> jarsBlobKeys = Collections.emptyList();
    List<String> artifactsBlobKeys;

    DependencyUploader uploader = new DependencyUploader();
    try {
        uploader.init();

        jarsBlobKeys = uploadDependencyJarsToBlobStore(uploader);

        artifactsBlobKeys = uploadDependencyArtifactsToBlobStore(uploader);
    } catch (Throwable e) {
        // remove uploaded jars blobs, not artifacts since they're shared across the cluster
        uploader.deleteBlobs(jarsBlobKeys);
        uploader.shutdown();
        throw e;
    }

    try {
        setDependencyBlobsToTopology(topology, jarsBlobKeys, artifactsBlobKeys);
        submitTopologyInDistributeMode(name, topology, opts, progressListener, asUser, conf, serConf, client);
    } catch (AlreadyAliveException | InvalidTopologyException | AuthorizationException e) {
        // remove uploaded jars blobs, not artifacts since they're shared across the cluster
        // Note that we don't handle TException to delete jars blobs
        // because it's safer to leave some blobs instead of topology not running
        uploader.deleteBlobs(jarsBlobKeys);
        throw e;
    } finally {
        uploader.shutdown();
    }
}

  先将配置文件改为json格式的string,然后获取Nimbus client对象,检查拓扑名称是否已经存在,将jar包上传BlobStore,调用submitTopologyInDistributeMode正式向NimbusClient提交请求:

private static void submitTopologyInDistributeMode(String name, StormTopology topology, SubmitOptions opts,
                                                   ProgressListener progressListener, String asUser, Map conf,
                                                   String serConf, NimbusClient client) throws TException {
    try {
        String jar = submitJarAs(conf, System.getProperty("storm.jar"), progressListener, client);
        LOG.info("Submitting topology {} in distributed mode with conf {}", name, serConf);
        Utils.addVersions(topology);
        if (opts != null) {
            client.getClient().submitTopologyWithOpts(name, jar, serConf, topology, opts);
        } else {
            // this is for backwards compatibility
            client.getClient().submitTopology(name, jar, serConf, topology);
        }
        LOG.info("Finished submitting topology: {}", name);
    } catch (InvalidTopologyException e) {
        LOG.warn("Topology submission exception: {}", e.get_msg());
        throw e;
    } catch (AlreadyAliveException e) {
        LOG.warn("Topology already alive exception", e);
        throw e;
    }
}

  该方法中,先将jar包上传至nimbus,然后向nimbus提交拓扑。

  Nimbus接受Topology提交时,Nimbus设置Topylogy状态为静态的,jar包和configs文件会放到到stormdist/{topology id}这个目录下,然后写任务–>组件映射到Zookeeper,创建一个Zookeeper目录使得任务可以心跳。
  然后Nimbus将任务分配给各个Supervisor节点机器,由Supervisor启动具体干活的Worker。一旦Topologies分配,会写入数据到zookeeper,以便集群知道Topology是活跃的和可以从spouts中emit元组(tuple)。

  运行“storm kill”这个命令,仅仅只是调用Nimbus的Thirft接口去kill掉相对应的Topology。
  Nimbus接受到kill命令,会将”kill”事务应用到topology上,修改Topology的状态为”killed”以及将“remove”事件列入到未来几秒钟的计划中,即未来几秒后会触发remove时间。这里的kill实际上停止闲相关的Worker。
  默认kill的等待时间是Topology消息的超时时间,但是可以通过storm kill命令中的-w标志对其进行重写,设置了以上参数之后,topology会在指定的等待时间停止运行。这样给了Topology一个机会在shutdown workers之后完成当前没有处理完成的任务;删除Topology以及清理zookeeper中的分配信息和静态信息;清理存储在本地的心跳dir和jar/configs。

Spout与Bolt

  在定义Topology实例过程中,就指定了Spout实例和Bolt实例。
  在提交Topology实例给Nimbus的过程中,会调用TopologyBuilder实例的createTopology()方法,以获取定义的Topology实例。
  在实例化Topology的过程中,就会实例化SpoutBolt(在Nimbus机器上实例化的),并序列化。会调用SpoutBolt实例上的declareOutputFields()方法和getComponentConfiguration()方法。declareOutputFields()方法配置Spout和Bolt实例的输出,getComponentConfiguration()方法输出特定于Spout和Bolt实例的配置参数值对。
  在Worker Node上运行的thread,从Nimbus上复制序列化后得到的字节码文件,从中反序列化得到Spout和Bolt实例,实例的输出配置和实例的配置参数值对等数据,在thread中Spout和Bolt实例的declareOutputFields()getComponentConfiguration()不会再运行
  
  在thread中,反序列化得到一个Spout实例后,它会先运行Spout实例的open()方法,在这个方法调用中,需要传入一个SpoutOutputCollector实例,后面使用该SpoutOutputCollector实例输出Tuple。然后Spout实例处于 deactivated 模式,过段时间会变成 activated 模式,此时会调用Spout实例的activate()方法。接下来在该thread中按配置数量建立task集合,在每个task中循环调用线程持有Spout实例的nextTuple()ack()fail()方法。任务处理成功,调用ack();任务处理失败,调用fail()
  在运行过程中,如果发送一个失效命令给Worker,那么Worker所持有的Spout实例会变成处于 deactivated 模式,并且会调用Spout实例的deactivate()方法。在关闭一个Worker时,Worker所持有的Spout实例会调用close()方法。不过如果是强制关闭,这个close()方法有可能不会被调用到。

  而对于Bolt,反序列化得到一个Bolt实例后,它会先运行Bolt实例的prepare()方法,在这个方法调用中,需要传入一个OutputCollector实例,后面使用该OutputCollector实例输出Tuple。接下来在该thread中按照配置数量建立task集合,然后在每个task中就会循环调用thread所持有Bolt实例的execute()方法。

  一般初始化操作应该在prepare/open方法中进行,而不是在实例化的时候进行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值