源码查看的是1.0.3版本的jar
1、Client端提交Topology到nimbus
调用命令:
storm jar WordCount.jar storm.starter.storm.starter wordcount
实际上调用的是:
storm -client WordCount.jar storm.starter.storm.starter wordcount
2、通过TopologyBuilder将Spout和Bolt按照一定的逻辑顺序构建Topology程序
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout", new RandomIntegerSpout());
builder.setBolt("partialsum", new StatefulSumBolt("partial"), Integer.valueOf(1)).shuffleGrouping("spout");
builder.setBolt("printer", new PrinterBolt(), Integer.valueOf(2)).shuffleGrouping("partialsum");
builder.setBolt("total", new StatefulSumBolt("total"), Integer.valueOf(1)).shuffleGrouping("printer");
3、通过调用TopologyBuilder的createTopology()方法,获取StormTopology实例对象。源码如下:
// 该方法用于创建Topology对象
public StormTopology createTopology() {
ComponentCommon common;
java.util.Map boltSpecs = new HashMap();
java.util.Map spoutSpecs = new HashMap();
maybeAddCheckpointSpout();
for (String boltId : this._bolts.keySet()) {
IRichBolt bolt = (IRichBolt)this._bolts.get(boltId);
bolt = maybeAddCheckpointTupleForwarder(bolt);
common = getComponentCommon(boltId, bolt);
try {
maybeAddCheckpointInputs(common);
boltSpecs.put(boltId, new Bolt(ComponentObject.serialized_java(Utils.javaSerialize(bolt)), common));
} catch (RuntimeException wrapperCause) {
if ((wrapperCause.getCause() != null) && (NotSerializableException.class.equals(wrapperCause.getCause().getClass())))
{
throw new IllegalStateException("Bolt '" + boltId + "' contains a non-serializable field of type " + wrapperCause
.getCause().getMessage() + ", which was instantiated prior to topology creation. " + wrapperCause
.getCause().getMessage() + " should be instantiated within the prepare method of '" + boltId + " at the earliest.", wrapperCause);
}
throw wrapperCause;
}
}
for (String spoutId : this._spouts.keySet()) {
IRichSpout spout = (IRichSpout)this._spouts.get(spoutId);
common = getComponentCommon(spoutId, spout);
try {
spoutSpecs.put(spoutId, new SpoutSpec(ComponentObject.serialized_java(Utils.javaSerialize(spout)), common));
} catch (RuntimeException wrapperCause) {
if ((wrapperCause.getCause() != null) && (NotSerializableException.class.equals(wrapperCause.getCause().getClass())))
{
throw new IllegalStateException("Spout '" + spoutId + "' contains a non-serializable field of type " + wrapperCause
.getCause().getMessage() + ", which was instantiated prior to topology creation. " + wrapperCause
.getCause().getMessage() + " should be instantiated within the prepare method of '" + spoutId + " at the earliest.", wrapperCause);
}
throw wrapperCause;
}
}
// 把Spout和Bolt相关信息存放到map中,并返回Topology对象
StormTopology stormTopology = new StormTopology(spoutSpecs, boltSpecs, new HashMap());
stormTopology.set_worker_hooks(this._workerHooks);
return stormTopology;
}
4、开始提交任务,具体过程如下
(1)调用StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.createTopology());提交任务(这种提交方式是集群下的提交)
submitTopologyWithProgressBar方法:
public static void submitTopologyWithProgressBar(String name, Map stormConf, StormTopology topology, SubmitOptions opts)
throws AlreadyAliveException, InvalidTopologyException, AuthorizationException
{
// 在此方法中有调用了submitTopology方法
submitTopology(name, stormConf, topology, opts, new ProgressListener()
{
public void onStart(String srcFile, String targetFile, long totalBytes) {
System.out.printf("Start uploading file '%s' to '%s' (%d bytes)\n", new Object[] { srcFile, targetFile, Long.valueOf(totalBytes) });
}
public void onProgress(String srcFile, String targetFile, long bytesUploaded, long totalBytes)
{
int length = 50;
int p = (int)(length * bytesUploaded / totalBytes);
String progress = StringUtils.repeat("=", p);
String todo = StringUtils.repeat(" ", length - p);
System.out.printf("\r[%s%s] %d / %d", new Object[] { progress, todo, Long.valueOf(bytesUploaded), Long.valueOf(totalBytes) });
}
public void onCompleted(String srcFile, String targetFile, long totalBytes)
{
System.out.printf("\nFile '%s' uploaded to '%s' (%d bytes)\n", new Object[] { srcFile, targetFile, Long.valueOf(totalBytes) }); } } );
}
(2) submitTopologyWithProgressBar方法中又调用了StormSubmitter的submitTopologyf方法。
submitTopology方法:
public static void submitTopology(String name, Map stormConf, StormTopology topology, SubmitOptions opts, ProgressListener progressListener)
throws AlreadyAliveException, InvalidTopologyException, AuthorizationException
{
submitTopologyAs(name, stormConf, topology, opts, progressListener, null);
}
(3)而在submitTopology方法又调用了submitTopology的submitTopologyAs方法
submitTopologyAs方法:
public static void submitTopologyAs(String name, Map stormConf, StormTopology topology, SubmitOptions opts, ProgressListener progressListener, String asUser)
throws AlreadyAliveException, InvalidTopologyException, AuthorizationException, IllegalArgumentException
{
// 检查Stormconf必须是json-serializable Json序列化对象
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中
stormConf.putAll(prepareZookeeperAuthentication(conf));
validateConfs(conf, topology);
Map passedCreds = new HashMap();
if (opts != null) {
Credentials tmpCreds = opts.get_creds();
if (tmpCreds != null)
passedCreds = tmpCreds.get_creds();
}
Map fullCreds = populateCredentials(conf, passedCreds);
if (!(fullCreds.isEmpty())) {
if (opts == null)
opts = new SubmitOptions(TopologyInitialStatus.ACTIVE);
opts.set_creds(new Credentials(fullCreds));
}
try {
// 判断nimbus是否为空,如果不为空,启动本地运行模式
if (localNimbus != null) {
LOG.info("Submitting topology " + name + " in local mode");
if (opts != null) {
localNimbus.submitTopologyWithOpts(name, stormConf, topology, opts);
}
else
localNimbus.submitTopology(name, stormConf, topology);
LOG.info("Finished submitting topology: " + name);
} else {
String serConf = JSONValue.toJSONString(stormConf);
// 检查Topology的名称在集群上是否存在,如果存在抛出异常
if (topologyNameExists(conf, name, asUser))
throw new RuntimeException("Topology with name `" + name + "` already exists on cluster");
// 调用submitJarAs方法提交jar文件
String jar = submitJarAs(conf, System.getProperty("storm.jar"), progressListener, asUser);
try { NimbusClient client = NimbusClient.getConfiguredClientAs(conf, asUser); Object localObject1 = null;
try { LOG.info("Submitting topology " + name + " in distributed mode with conf " + serConf);
if (opts != null) {
client.getClient().submitTopologyWithOpts(name, jar, serConf, topology, opts);
}
else
client.getClient().submitTopology(name, jar, serConf, topology);
LOG.info("Finished submitting topology: " + name); } catch (Throwable localThrowable2) { } finally {
if (client != null) if (localObject1 != null) try { client.close(); } catch (Throwable localThrowable3) { localObject1.addSuppressed(localThrowable3); } else client.close();
}
} 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;
}
}
} catch (TException e) {
throw new RuntimeException(e);
}
invokeSubmitterHook(name, asUser, conf, topology);
}
在submitTopology()方法中,做了一下工作:
1)检验Stormconf,必须是json-serializableJson的序列化对象 Utils.isValidConf(stormConf)
2)判断Topology的运行模式
//STONE_NOTE如果localNimbus不为空的话,调用本地模式运行 localNimbus.submitTopology(name,null,serConf,topology);
3)如果为分布式集群模式运行
//STONE_NOTE检测Topology的名称在集群上是否存在 topologyNameExists(client,conf,name)
//STONE_NOTE调用submitJar方法,提交jar文件
submitJar(client,conf);
//STONE_NOTE新的提交方式,携带opts参数 提交Topology任务
client.getClient().submitTopologyWithOpts(name,path,serConf,topology,opts);
最终任务提交完成!