storm源码剖析(3):topology启动过程

storm的topology启动过程是执行strom jar topology1.jar MAINCLASS ARG1 ARG2

鉴于前面已经分析了脚本的解析过程,现在重点分析topology1.jar的执行。

以storm-starter中的ExclamationTopology为例,来进行剖析:

public class ExclamationTopology {

  public static class ExclamationBolt extends BaseRichBolt {
    OutputCollector _collector;

    @Override
    public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
      _collector = collector;
    }

    @Override
    public void execute(Tuple tuple) {
      _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
      _collector.ack(tuple);
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
      declarer.declare(new Fields("word"));
    }


  }

  public static void main(String[] args) throws Exception {
    TopologyBuilder builder = new TopologyBuilder();

    builder.setSpout("word", new TestWordSpout(), 10);
    builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
    builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");

    Config conf = new Config();
    conf.setDebug(true);

    if (args != null && args.length > 0) {
      conf.setNumWorkers(3);

      StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
    }
    else {

      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology("test", conf, builder.createTopology());
      Utils.sleep(10000);
      cluster.killTopology("test");
      cluster.shutdown();
    }
  }
}

可以看到一个topology的启动包括三个步骤:

(1)创建TopologyBuilder,设置输入源spout,设置输出源bolt

(2)创建Config,设置配置项

(3)提交topology

创建TopologyBuilder

TopologyBuilder对象创建很简单,先来看看setSpout():

public SpoutDeclarer setSpout(String id, IRichSpout spout, Number parallelism_hint) {
        validateUnusedId(id);
        initCommon(id, spout, parallelism_hint);
        _spouts.put(id, spout);
        return new SpoutGetter(id);
    }

首先,判断componentId是否使用过了,如果使用过,则直接剖错。

然后,初始化Commponent:创建ComponentCommon对象,并设置属性,然后在TopologyBuilder 的成员变量Map<String, IRichSpout> _commons中记录下common,其key为componentId(这里为“word”)。代码如下:

private void initCommon(String id, IComponent component, Number parallelism) {
        ComponentCommon common = new ComponentCommon();
        common.set_inputs(new HashMap<GlobalStreamId, Grouping>());
        if(parallelism!=null) common.set_parallelism_hint(parallelism.intValue());
        Map conf = component.getComponentConfiguration();
        if(conf!=null) common.set_json_conf(JSONValue.toJSONString(conf));
        _commons.put(id, common); 
    }

其中ComponentCommon是使用thrift定义的,在storm.thrift中定义,代码如下:

struct ComponentCommon {
  1: required map<GlobalStreamId, Grouping> inputs;
  2: required map<string, StreamInfo> streams; //key is stream id
  3: optional i32 parallelism_hint; //how many threads across the cluster should be dedicated to this component

  // component specific configuration respects:
  // topology.debug: false
  // topology.max.task.parallelism: null // can replace isDistributed with this
  // topology.max.spout.pending: null
  // topology.kryo.register // this is the only additive one
  
  // component specific configuration
  4: optional string json_conf;
}

最后,在TopologyBuilder 的成员变量Map<String, IRichSpout> _spouts,记录下spout的记录。其中key也是componentId(这里为“word”)。

 

再来看看setBolt,与setSpout的处理一样,最终在TopologyBuilder 的成员变量Map<String, IRichSpout> _commons中记录下common,其key为componentId(这里为“exclaim1”);在TopologyBuilder 的成员变量Map<String, IRichSpout> _bolts,记录下bolt的记录。其中key也是componentId(这里为“exclaim1”).

之后,.shuffleGrouping("word")这部分,是调用setBolt返回的,BoltDeclarer中的shuffleGrouping。

         最终将会调用到grouping,其中streamId在这里没有指定,会使用"default"来替代。

public BoltDeclarer shuffleGrouping(StringcomponentId) {

   return shuffleGrouping(componentId, Utils.DEFAULT_STREAM_ID);

}

public BoltDeclarer shuffleGrouping(StringcomponentId, String streamId) {

   return grouping(componentId, streamId, Grouping.shuffle(newNullStruct()));

}

在这里grouping最后一个参数是生成了Grouping对象,并填充shuffle为NullStruct,其中Grouping是在storm.thrift定义的一个联合体,thrift会生成对应的java代码,内部定义了很多种grouping的方式。                                                                                                                                  

private BoltDeclarer grouping(StringcomponentId, String streamId, Grouping grouping)

{

    _commons.get(_boltId).put_to_inputs(new GlobalStreamId(componentId,streamId), grouping);

    return this;

}

grouing函数是将之前记录在_commons中的,bolt的componentId对应的ComponentCommon的键值对,取出来设置ComponentCommon中的inputs的值。以第一个setBolt为例,就是取出"exclaim1"这个componentId对应的ComponentCommon,将里面的inputs设置为,这个输入是从哪里来的,也就是"word"这个componentId,streamId为"default"的这个spout流作为第一个bolt的输入源。

创建Config

Config比较简单,继承自Map,通过setXxx()为自身添加配置。

在这个例子中有两个set函数的调用。

conf.setDebug(true);就是在Map中插入一条记录("topology.debug" -> "true"),标记是打开debug模式的。

conf.setNumWorkers(3);同样在Map中插入一条记录("topology.workers" -> 3),标记worker数为3个。

提交Topology--这才是重点

StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
(1)createTopology
builder.createTopology()利用之间构建的TopologyBuilder对象生成一个StormToplogy对象。
public StormTopology createTopology() {
        Map<String, Bolt> boltSpecs = new HashMap<String, Bolt>();
        Map<String, SpoutSpec> spoutSpecs = new HashMap<String, SpoutSpec>();
        for(String boltId: _bolts.keySet()) {
            IRichBolt bolt = _bolts.get(boltId);
            ComponentCommon common = getComponentCommon(boltId, bolt);
            boltSpecs.put(boltId, new Bolt(ComponentObject.serialized_java(Utils.serialize(bolt)), common));
        }
        for(String spoutId: _spouts.keySet()) {
            IRichSpout spout = _spouts.get(spoutId);
            ComponentCommon common = getComponentCommon(spoutId, spout);
            spoutSpecs.put(spoutId, new SpoutSpec(ComponentObject.serialized_java(Utils.serialize(spout)), common));
            
        }
        return new StormTopology(spoutSpecs,
                                 boltSpecs,
                                 new HashMap<String, StateSpoutSpec>());
    }

需要说明的是,StormTopology也是storm.thrift中定义的一个struct结构,定义如下:

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;
}
(2)submitTopology
提交到集群会调用StormSubmitter.submitTopology()
public static void submitTopology(String name, Map stormConf, StormTopology topology) throws AlreadyAliveException, InvalidTopologyException {
        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);
        try {
            String serConf = JSONValue.toJSONString(stormConf);
            if(localNimbus!=null) {
                LOG.info("Submitting topology " + name + " in local mode");
                localNimbus.submitTopology(name, null, serConf, topology);
            } else {
                submitJar(conf);
                NimbusClient client = NimbusClient.getConfiguredClient(conf);
                try {
                    LOG.info("Submitting topology " +  name + " in distributed mode with conf " + serConf);
                    client.getClient().submitTopology(name, submittedJar, serConf, topology);
                } finally {
                    client.close();
                }
            }
            LOG.info("Finished submitting topology: " +  name);
        } catch(TException e) {
            throw new RuntimeException(e);
        }
    }

具体流程为:

1)检验传进来的配置合法性,并读取命令行配置storm.options项的值、读取默认配置default.yaml、读取storm.yaml,将这些所有的配置项都添加到conf

中。

2)调用submitJar(conf),上传jar到master。

a. 具体是通过获取命令行参数“storm.jar”来得到要上传的jar;

b. 获取Config.NIMBUS_HOST和Config.NIMBUS_THRIFT_PORT值,创建NimbusClient。在内部是封装了访问Nimbus这个rpc server(基于thrift)的rpc client,在NimbusClient构造时,就创建了rpcclient并建立与rpc server的连接;

c. 调用client.getClient().beginFileUpload()通知要上传文件,Nimbus会返回一个上传的路径,之后分段读取jar文件,调用uploadChunk上传到nimbus所告知的那个路径,jar文件数据都上传完毕调用finishFileUpload告知nimbus对那个路径的文件已上传完毕,最后关闭rpc连接。其中beginFileUpload,uploadChunk,finishFileUpload都是storm.thrift定义的service Nimbus中的方法,其中Nimbus.Iface是在 Nimbus.clj被实现了。

d. 成功上传jar文件后,会再次创建的一个rpc client调用Nimbus上的submitTopology方法,这个方法也是在storm.thrft中service Nimbus。调用这个Nimbus上的这个方法可以理解为通知Nimbus去运行这个topology。通知的时候,会带上name,这个name就是topology的名字。

private static void submitJar(Map conf) {
        if(submittedJar==null) {
            LOG.info("Jar not uploaded to master yet. Submitting jar...");
            String localJar = System.getProperty("storm.jar");
            submittedJar = submitJar(conf, localJar);
        } else {
            LOG.info("Jar already uploaded to master. Not submitting jar.");
        }
    }

public static String submitJar(Map conf, String localJar) {
        if(localJar==null) {
            throw new RuntimeException("Must submit topologies using the 'storm' client script so that StormSubmitter knows which jar to upload.");
        }
        NimbusClient client = NimbusClient.getConfiguredClient(conf);
        try {
            String uploadLocation = client.getClient().beginFileUpload();
            LOG.info("Uploading topology jar " + localJar + " to assigned location: " + uploadLocation);
            BufferFileInputStream is = new BufferFileInputStream(localJar);
            while(true) {
                byte[] toSubmit = is.read();
                if(toSubmit.length==0) break;
                client.getClient().uploadChunk(uploadLocation, ByteBuffer.wrap(toSubmit));
            }
            client.getClient().finishFileUpload(uploadLocation);
            LOG.info("Successfully uploaded topology jar to assigned location: " + uploadLocation);
            return uploadLocation;
        } catch(Exception e) {
            throw new RuntimeException(e);            
        } finally {
            client.close();
        }
    }

public static NimbusClient getConfiguredClient(Map conf) {
        String nimbusHost = (String) conf.get(Config.NIMBUS_HOST);
        int nimbusPort = Utils.getInt(conf.get(Config.NIMBUS_THRIFT_PORT));
        return new NimbusClient(nimbusHost, nimbusPort);
    }
    
public NimbusClient(String host, int port) {
        try {
            if(host==null) {
                throw new IllegalArgumentException("Nimbus host is not set");
            }
            conn = new TFramedTransport(new TSocket(host, port));//创建rpc连接
            client = new Nimbus.Client(new TBinaryProtocol(conn));//创建rpc客户端
            conn.open(); //打开连接
        } catch(TException e) {
            throw new RuntimeException(e);
        }
    }

到此,一个编写有topology任务的jar文件就上传提交到nimbus,接下来的工作就是由nimbus将topology分发给supervisors去执行。请关注后续的剖析。

转载于:https://www.cnblogs.com/jerryshao2015/p/4432966.html

掌握Storm,开启大数据领域实时处理新征程 本文旨在帮助零基础或初级开发者理解Storm的核心原理,掌握基本使用方法,并能将其应用到实际业务场景中。内容覆盖Storm的设计思想、关键组件、开发实战及行业应用,不涉及过深的源码解析(适合后续进阶学习)。本文将按照“概念理解→原理剖析→实战演练→场景应用”的逻辑展开:先用生活案例引出Storm的核心组件;再通过流程图和代码示例讲解技术细节;最后结合真实业务场景说明其价值。Topology(拓扑):Storm中的“任务蓝图”,定义了数据从输入到输出的完整处理流程(类似工厂的生产线设计图)。 阅读详情

相关推荐

将一维数据(序列)转化为二维数据(图像)的方法汇总GAFS, MTF, Recurrence plot,STFT

虽然深度学习方法(1D CNN, RNN, LSTM 等)可以直接处理一维数据,但是当前的深度学习方法主要还是处理二维结构数据的,特别是在计算机视觉CV以及自然语言处理NLP领域,各种各样的方法层出不穷。因此,如果能够将一维序列数据转化为二维(图像)数据, 则可以直接结合CV以及NLP领域的方法,是不是很有趣! GAF, GASF, GADF, MTF, Recurrence Plot, STFT, 短时傅里叶变换

MasterQKK 5万+

storm-0.8.2源码分析之topology启动

topology启动          一个topology的启动包括了三个步骤          1)创建TopologyBuilder,设置输入源,输出源          2)获取config          3)提交topology(这里不考虑LocalCluster本地模式)            以storm.starter的ExclamationTopology为例:

chlaws的专栏 7991

CIC-IDS数据集特征介绍

###1、简介 通信安全机构(CSE)与加拿大网络安全研究所(CIC)合作项目,该项目对自1998年以来现有的11个数据集的评估表明,大多数数据集(比如经典的KDDCUP99,NSLKDD等)已经过时且不可靠。其中一些数据集缺乏流量多样性和容量,一些数据集没有涵盖各种已知的攻击,而另一些数据集将数据包有效载荷数据匿名化,这不能反映当前的趋势。有些还缺少特征集和元数据。 CIC-IDS-2017数据集包含良性和最新的常见攻击,类似真实世界数据(PCAPs)。 它的数据采集截至2017...

蓝亚之舟的博客 3万+

Storm杂谈之Topology的启动过程(一)

简单介绍了storm topology启动时的大概过程

iTer的专栏 5035

AVL Cruise 2020.1 安装教程

AVL Cruise 2020.1 安装教程

chengkai730的博客 9477

因果推断--PSM的原理和应用(二)

上一篇介绍了DID,本文介绍和DID可一起搭配使用的一种因果推断方法PSM。在正式介绍PSM之前,先来简单回顾一下为什么需要因果推断以及如何做因果推断。我们都知道相关非因果,比起相关我们更希望知道两个事件之间的因果关系,有了确切的因果关系,才能知道对A如何操作才能引起B的变化。解决因果推断问题,目前主要有两种框架,Rubin虚拟事实模型和Pearl因果图模型。站在数据分析的角度上,Rubin虚拟事实模型更容易理解,其核心思想是寻找恰当的对照组。

baidu_26137595的博客 1万+

Storm应用系列之——集成Kafka

本文系原创系列,转载请注明。 原帖地址:http://blog.youkuaiyun.com/xeseo 前言 在前面Storm系列之——基本概念一文中,提到过Storm的Spout应该是源源不断的取数据,不能间断。那么,很显然,消息队列系统、分布式内存系统或内存数据库是作为其数据源的很好的选择。本文就如何集成Kafka进行介绍。 Kafka的基本介绍:http://blog.csdn

Edison Xu 2万+

逆变器专题(6)-正负序分离(二阶广义积分器DSOGI)

相应仿真原件请移步资源下载DSOGI作为一种常用的正负序分离方法,其可以在电压三相不平衡的状态下实现较为精准的锁相环。

cyc19980105的博客 8803

STORM启动与部署TOPOLOGY

启动ZOOPKEEPER zkServer.sh start 启动NIMBUS storm nimbus & 启动SUPERVISOR storm supervisor & 启动UI storm ui & 部署TOPOLOGY storm jar /opt/hadoop/loganalyst/storm-dependend/data/teststorm-1.0

工作点滴 5484

[EdgeAI] NXP eIQ 机器学习Toolkit (一):准备篇

eIQ™机器学习(ML)软件开发环境支持在恩智浦EdgeVerse™微控制器和微处理器(包括i.MX RT跨界MCU和i.MX系列应用处理器)上使用ML算法。eIQ ML软件包括称为eIQ Toolkit的ML工作流工具以及推理引擎、神经网络编译器和优化库。............

HowieXue 薛永浩的博客 1万+

智联招聘Python岗位数据采集:基于API请求的校园招聘信息爬取实战

本项目开发了一个智联招聘Python岗位校园招聘数据采集系统,采用requests库直接调用API接口获取结构化数据。系统通过分析API接口结构,配置完整的请求头、Cookie和身份验证参数,实现了10页数据的批量采集。采集内容包括工作名称、薪资范围、企业信息等10个关键字段,并存储为Excel格式。项目严格遵守网络爬虫规范,合理控制请求频率,数据仅用于技术学习和就业分析。技术实现涉及API逆向工程、JSON数据处理、防御性编程等核心技能,为学生职业规划和教育机构教学改革提供数据支持。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 625

Storm系列(三)Topology提交过程

提交示例代码: 1 publicstaticvoidmain(String[]args)throwsException{ 2 TopologyBuilderbuilder=newTopologyBuilder(); ...

weixin_30467087的博客 237

【OpenClaw企业级智能体实战】第24篇:一人公司实战——用Agent Teams同时管理产品、运营、销售(附16个Agent配置方案+全流程指令模板)

当AI智能体从“单一工具”进化为“协同团队”,“一人公司”已从商业概念变为落地现实。2025年中国超1200万个体创业者采用OPC模式,靠AI团队突破人力边界。本文基于OpenClaw Agent Teams框架,拆解“1总指挥+15执行者”的三层AI组织架构,提供覆盖产品、运营、销售全业务的16个Agent分工矩阵、可直接复制的部署代码、通信配置方案与全流程指令模板。通过虚拟案例验证:单人+AI团队可实现月入26万的商业闭环,AI承担90%标准化工作,人力成本降低75000元/月,ROI超3200%。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 940

Storm源码浅析之topology的提交

最近一直在读twitter开源的这个分布式流计算框架——storm的源码,还是有必要记录下一些比较有意思的地方。我按照storm的主要概念进行组织,并且只分析我关注的东西,因此称之为浅析。 一、介绍 Storm的开发语言主要是Java和Clojure,其中Java定义骨架,而Clojure编写核心逻辑。源码统计结果: &lt;!– Code highlighting produce...

caodaoxi的专栏 101

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

storm学习二 storm系统的启动详解

这些天对storm源码进行了部分解读,做一个阶段性的总结。 nimbus启动过程:  sd.join(); 1 验证是否是本地模式,如果是,则抛出异常,退出,否则启动nimbus 2 addHook, 增加nimbus退出时的清理工作{1, 停止线程,2 停止thrift服务,3 断开zk} 3 构造出一个nimbusData的数据结构{线程池,配置文件,上传下载文件的timeCac

西红柿炒土豆 871

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

JStorm源码分析(一)Storm执行脚本

JStorm源码分析(一):Storm执行脚本 storm脚本 Storm脚本是python脚本 调用storm脚本时,执行其中的main方法,mian方法源代码如下: main方法中有两个参数: COMMAND = args[0] ARGS = args[1:] 所有的COMMAND: COMMANDS = { “jar”: jar, “kill”: kill, “she...

Oeljeklaus的博客 879

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

数据工程师实战指南:Hadoop、Spark、Flink等五大框架生产调优与避坑

大数据(Big Data)指在分布式环境下对海量、高速、多样数据进行采集、存储、计算与服务的系统性工程能力。其核心原理在于通过分而治之(Shuffle/Partition)、容错重试(Speculative Execution/Checkpointing)和统一资源调度(YARN/K8s)保障SLA。技术价值体现在降低TCO、提升分析时效性与支撑实时决策闭环。典型应用场景包括电商用户行为分析、金融风控实时拦截、IoT设备时序处理等。本文聚焦Hadoop、Spark、Flink、Hive、Storm五大高频框

weixin_30772105的博客 777

JStorm源码分析(三)Nimbus的任务分配过程

JStorm源码分析(三):Nimbus的任务分配过程 1 . 在 T o p o l o g y 的 任 务 提 交 中 ,最 后 调 用 S t o r m S u b m i t t e r 的 submitTopology方 法 将 任 务 提 交 给 nimbus;实际上,在StormSubmitter的submitTopology中,是NimbusClient通过RPC(远程过程调 ...

Oeljeklaus的博客 991

性能优化的本质:从线程模型与数据流拆解系统瓶颈

在分布式系统中,性能问题往往不是由框架本身导致,而是源于对数据流动本质和线程执行机制的误判。理解‘数据如何被抽取、处理、落库’这一基础链路,比熟记Storm参数或RocketMQ配置更为关键;掌握线程生命周期、连接池竞争、IO与CPU密集型任务的调度差异,则是定位阻塞、上下文切换、资源争用等真实瓶颈的核心能力。本文以真实生产案例切入,聚焦Java服务中线程模型重构、连接池解耦、异步缓冲设计等工程实践,揭示如何通过日志三维分析(事件-时间-线程)、物理动作拆解(抽水→过滤→存池)和可追踪线程命名等方法,将模糊

diedangxiang4092的博客 528

storm使用(二)–使用java操作storm

storm使用(二)–使用java操作storm 文章目录storm使用(二)--使用java操作storm一、简介二、storm特点2.1 元组可靠性保证2.2 容错性2.3 可与任何语言使用三、storm基础接口3.1 org.apache.storm.topology.IComponent接口3.2 org.apache.storm.spout.ISpout接口3.3 org.apache....

panda-star的博客 2717

8.storm中不同的流分组方式

package backtype.storm.topology; import backtype.storm.generated.GlobalStreamId; import backtype.storm.generated.Grouping; import backtype.storm.grouping.CustomStreamGrouping; import back

爱[黎姿]的程序员 1051

Storm架构与运行原理

一、Storm简介     Storm是一个免费并开源的分布式实时计算系统。利用Storm可以很容易做到可靠地处理无限的数据流,像Hadoop批量处理大数据一样,Storm可以实时处理数据。 Storm 很简单,可用于任意编程语言。Apache Storm 采用 Clojure 开发。Storm 有很多应用场景,包括实时数据分析、联机学习、持续计算、分布式 RPC、ETL 等。

一路前行 3万+

关于Storm Stream grouping

在Storm中, 开发者可以为上游spout/bolt发射出的tuples指定下游bolt的哪个/哪些task(s)来处理该tuples。这种指定在storm中叫做对stream的分组,即stream grouping,分组方式主要有以下7种 Shuffle Grouping 或None GroupingFields GroupingAll GroupingGlobal GroupingLo

kqdongnanf的专栏 1865

java如何在storm中运行_storm从入门到放弃教程(3)--初运行Topologies (拓扑)

概述上一篇【 基础概念详细介绍 】 博文连接:https://my.oschina.net/u/2342969/blog/874052本文将对Topologies (拓扑)进行详细的解释,此博文需要有一定storm基础,如需了解基础,请阅读上一篇博文,其中将会包含内容如下:TopologyBuilder如何在生产集群运行一个拓扑本地运行拓扑主体简单使用TopologyBuilder为storm声明...

weixin_39791653的博客 235

Storm常见模式——流聚合

流聚合(stream join)是指将具有共同元组(tuple)字段的数据流(两个或者多个)聚合形成一个新的数据流的过程。 从定义上看,流聚合和SQL中表的聚合(table join)很像,但是二者有明显的区别:table join的输入是有限的,并且join的语义是非常明确的;而流聚合的语义是不明确的并且输入流是无限的。 数据流的聚合类型跟具体的应用有关。一些应用把两个流发出的所有的tupl...

weixin_34080571的博客 483

storm 常用类

获得 org.apache.storm storm-core 0.9.5 常用类 backtype.storm.topology.TopologyBuilder 用来建立topology。 SpoutDeclarer backtype.storm.topology.TopologyBuilder.setSpout(String id, IRichSpout spout, N

yichudu 2608
上一篇: storm源码剖析(2):storm的配置项
下一篇: 32位机和64位机的区别及基本数据类型占字节数
dgit3228
博客等级 码龄12年 2粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值