【源码分析】storm拓扑运行全流程源码分析
@(STORM)[storm]
一、拓扑提交流程
拓扑提交的总体流程如下:
1、客户端通过thrift RPC提交topology的配置及jar包到nimbus。
2、nimbus针对该topology建立本地目录。
3、nimbus调度器根据topology的配置计算task,并把task分配到不同的worker上,调度的结果写入zookeeper。
4、zk上建立assignment节点,存储task和supervisor中的worker的对应关系。同时在zk上创建workerbeats节点来监控worker的心跳。
5、supervisor去zk上获取分配的task信息,启动一个或者多个worker来执行。
6、每个worker上运行一个或多个executor,每个executor对应一个线程,worker内部的executor之间通过DisrupterQueue进行通信,不同worker间默认采用netty来通信。
7、executor运行一个或者多个task(spout/bolt)
到此,topology就正式运行起来了。
具体流程图如下:(参考自《storm技术内幕与大数据实践》P96)
本文介绍了通过调用storm jar如何向nimbus提交拓扑的过程,即上述的第一步,主要的工作是加载配置信息,classpath,并将其与用户的jar包通过thrift协调上传至nimbus,等待nimbus的调用。
(一)storm.py
在这部分,请尤其注意classpath的设置。
依次将下列内容加入classpath中:
\$STORM_HOME
\$STORM_HOME/lib
\$STORM_HOME/extlib
用户代码的jar包
~/.storm
\$STORM_HOME/bin
详见下面的分析。
1、storm jar
用户可以通过storm jar命令向storm集群提交一个拓扑,如:
/home/hadoop/storm/bin/storm jar storm-starter-topologies-0.9.4.jar storm.starter.WordCountTopology word-count
其实,storm执行的是bin/目录下的storm.py文件
2、def jar
jar函数只有一行,就是执行exec_storm_class函数。
def jar(jarfile, klass, *args):
exec_storm_class(
klass,
jvmtype="-client",
extrajars=[jarfile, USER_CONF_DIR, STORM_BIN_DIR],
args=args,
daemon=False,
jvmopts=JAR_JVM_OPTS + ["-Dstorm.jar=" + jarfile])
其中的几个变量为:
USER_CONF_DIR = os.path.expanduser("~" + os.sep + ".storm")
STORM_BIN_DIR = os.path.join(STORM_DIR, "bin")
因此用户jar包,~/.storm及$STORM_HOME/bin目录下的jar包会被自动加载到classpath中。
3、exec_storm_class
def exec_storm_class(klass, jvmtype="-server", jvmopts=[], extrajars=[], args=[], fork=False, daemon=True, daemonName=""):
global CONFFILE
storm_log_dir = confvalue("storm.log.dir",[CLUSTER_CONF_DIR])
if(storm_log_dir == None or storm_log_dir == "nil"):
storm_log_dir = os.path.join(STORM_DIR, "logs")
all_args = [
JAVA_CMD, jvmtype,
"-Ddaemon.name=" + daemonName,
get_config_opts(),
"-Dstorm.home=" + STORM_DIR,
"-Dstorm.log.dir=" + storm_log_dir,
"-Djava.library.path=" + confvalue("java.library.path", extrajars, daemon),
"-Dstor