streamsets Data Collecotor启动流程分析
来源:互联网 发布:夏威夷旅行社 知乎 编辑:程序博客网 时间:2024/06/07 00:24
-classpath ${BOOTSTRAP_CLASSPATH}
${SDC_JAVA_OPTS}
com.streamsets.pipeline.BootstrapMain \
-mainClass
${SDC_MAIN_CLASS}
-apiClasspath "${API_CLASSPATH}"
-containerClasspath "${CONTAINER_CLASSPATH}" \
-streamsetsLibrariesDir "${STREAMSETS_LIBRARIES_DIR}"
-userLibrariesDir "${USER_LIBRARIES_DIR}"
-configDir ${SDC_CONF} \
-libsCommonLibDir "${LIBS_COMMON_LIB_DIR}" ${EXTRA_OPTIONS}
注意这里SDC_JAVA_OPTS
SDC_JAVA_OPTS=${SDC_JAVA_OPTS:="-Xmx1024m"}
SDC_MAIN_CLASS=${SDC_MAIN_CLASS:="com.streamsets.datacollector.main.DataCollectorMain"}
SDC_SECURITY_MANAGER_ENABLED=${SDC_SECURITY_MANAGER_ENABLED:="true"}
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.dist.dir=${SDC_DIST}"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.resources.dir=${SDC_RESOURCES}"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.hostname=${SDC_HOSTNAME}"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.conf.dir=${SDC_CONF}"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.data.dir=${SDC_DATA}"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -Dsdc.log.dir=${SDC_LOG}"
BOOTSTRAP_JAR="${SDC_DIST}/libexec/bootstrap-libs/main/streamsets-datacollector-bootstrap-2.2.0.0.jar"
SDC_JAVA_OPTS="${SDC_JAVA_OPTS} -javaagent:${BOOTSTRAP_JAR}"
使用了-javaagent选项,关于javaAgent的介绍,这里有篇文章http://blog.csdn.net/ykdsg/article/details/12080071
大意是指你应用程序的入口类的Main方法执行之前,先执行javaAgent参数制定的jar包里MANIFEST.MF中敲定的类的premain方法
AgentJAR即BOOTSTRAP_JAR="${SDC_DIST}/libexec/bootstrap-libs/main/streamsets-datacollector-bootstrap-2.2.0.0.jar"
MANIFEST.MF的内容如下:
Manifest-Version: 1.0Premain-Class: com.streamsets.pipeline.BootstrapMainArchiver-Version: Plexus ArchiverBuilt-By: jenkinsCreated-By: Apache Maven 3.3.9Build-Jdk: 1.8.0_112
可以看到,agent类和应用程序类都是同一个com.streamsets.pipeline.BootstrapMain
当在命令行启动该代理jar时,VM会根据manifest中指定的代理类,使用于main类相同的系统类加载器(即ClassLoader.getSystemClassLoader()获得的加载器)加载代理类。在执行main方法前执行premain()方法。
public static void premain(String args, Instrumentation instrumentation) { if (BootstrapMain.instrumentation == null) { BootstrapMain.instrumentation = instrumentation; } else { throw new IllegalStateException("Premain method cannot be called twice (" + BootstrapMain.instrumentation + ")"); } }
其中方法参数args即命令中的options,类型为String(注意不是String[]),因此如果需要多个参数,需要在方法中自己处理(比如用";"分割多个参数之类);inst是运行时由VM自动传入的Instrumentation实例,可以用于获取VM信息
那么这里只是简单的将instrumentation对象hold住,并没有做其它操作,因为BootstrapMain只是负责bootstrap的任务,那么真正的应用入口类是通过-mainClass指定的,
mainClass即 com.streamsets.datacollector.main.DataCollectorMain ,instrumentation是BootstrapMain通过反射传递给主类的setContext方法,
public static void setContext(ClassLoader apiCL, ClassLoader containerCL, List<? extends ClassLoader> moduleCLs, Instrumentation instrumentation) { MemoryUsageCollector.initialize(instrumentation); RuntimeModule.setStageLibraryClassLoaders(moduleCLs); }
如果继续追踪代码,会发现主要使用
instrumentation.getObjectSize(obj)方法获取对象的内存占用情况,以便精确控制pipeline内存占用情况。 javaAgent参数的使用,目的简单说就是为了获取到instrumentation对象,然后用这个对象做一些事情。
bootstrapMain除了充当javaAgent,那么它还负责把各种classpath汇总好,作为参数传递给DataCollectorMain,因为dataCollector下面有很多的jar包,而streamsets支持hbase,hadoop,kafka等系统多种版本的客户端,而这种客户端都是运行在同一个jvm里面,开发同学都知道jar包依赖冲突的问题,跟nifi一样,streamsets给pipeline上面没一个stage配置了一个classloader,具体是怎么做的呢?
String apiClasspath = null; String containerClasspath = null; String streamsetsLibrariesDir = null; String streamsetsLibrariesExtraDir = null; String userLibrariesDir = null; String configDir = null; String libsCommonLibDir = null;
那么主要分上面几类路径,里面分别存放了各个阶段需要的jar包
List<URL> apiUrls = getClasspathUrls(apiClasspath); List<URL> containerUrls = getClasspathUrls(containerClasspath);
上面首先获取到api和container的所有jar包的位置集合
├── api-lib
│ ├── annotations-java5-15.0.jar
│ ├── log4j-1.2.17.jar
│ ├── metrics-core-3.1.0.jar
│ ├── slf4j-api-1.7.7.jar
│ ├── slf4j-log4j12-1.7.7.jar
│ └── streamsets-datacollector-api-2.2.0.0.jar
和
├── container-lib
│ ├── activation-1.1.jar
│ ├── annotations-2.0.1.jar
│ ├── aopalliance-repackaged-2.4.0-b34.jar
│ ├── asm-5.0.3.jar
│ ├── commons-beanutils-1.9.3.jar
│ ├── commons-codec-1.10.jar
│ ├── commons-collections-3.2.2.jar
│ ├── commons-compress-1.10.jar
│ ├── commons-configuration2-2.0.jar
│ ├── commons-el-1.0.jar
│ ├── commons-io-2.4.jar
│ ├── commons-lang3-3.3.2.jar
│ ├── commons-logging-1.2.jar
│ ├── commons-pool2-2.4.1.jar
│ ├── dagger-1.2.2.jar
│ ├── google-http-client-1.22.0.jar
│ ├── google-http-client-jackson2-1.22.0.jar
│ ├── guava-18.0.jar
│ ├── hk2-api-2.4.0-b34.jar
│ ├── hk2-locator-2.4.0-b34.jar
│ ├── hk2-utils-2.4.0-b34.jar
│ ├── httpclient-4.5.2.jar
│ ├── httpcore-4.4.4.jar
│ ├── jackson-annotations-2.4.3.jar
│ ├── jackson-core-2.4.3.jar
│ ├── jackson-databind-2.4.3.jar
│ ├── jackson-dataformat-xml-2.4.3.jar
│ ├── jackson-dataformat-yaml-2.4.5.jar
│ ├── jackson-datatype-joda-2.4.3.jar
│ ├── jackson-jaxrs-base-2.5.4.jar
│ ├── jackson-jaxrs-json-provider-2.5.4.jar
│ ├── jackson-module-jaxb-annotations-2.4.3.jar
│ ├── javassist-3.19.0-GA.jar
│ ├── javax.annotation-api-1.2.jar
│ ├── javax.inject-1.jar
│ ├── javax.inject-2.4.0-b34.jar
│ ├── javax.servlet-api-3.1.0.jar
│ ├── javax.ws.rs-api-2.0.1.jar
│ ├── jersey-client-2.22.2.jar
│ ├── jersey-common-2.22.2.jar
│ ├── jersey-container-servlet-2.22.2.jar
│ ├── jersey-container-servlet-core-2.22.2.jar
│ ├── jersey-entity-filtering-2.22.2.jar
│ ├── jersey-guava-2.22.2.jar
│ ├── jersey-media-jaxb-2.22.2.jar
│ ├── jersey-media-json-jackson-2.22.2.jar
│ ├── jersey-media-multipart-2.22.2.jar
│ ├── jersey-server-2.22.2.jar
│ ├── jetty-client-9.2.17.v20160517.jar
│ ├── jetty-continuation-9.2.17.v20160517.jar
│ ├── jetty-http-9.2.17.v20160517.jar
│ ├── jetty-io-9.2.17.v20160517.jar
│ ├── jetty-jaas-9.2.17.v20160517.jar
│ ├── jetty-rewrite-9.2.17.v20160517.jar
│ ├── jetty-security-9.2.17.v20160517.jar
│ ├── jetty-server-9.2.17.v20160517.jar
│ ├── jetty-servlet-9.2.17.v20160517.jar
│ ├── jetty-servlets-9.2.17.v20160517.jar
│ ├── jetty-util-9.2.17.v20160517.jar
│ ├── jetty-webapp-9.2.17.v20160517.jar
│ ├── jetty-xml-9.2.17.v20160517.jar
│ ├── joda-time-2.3.jar
│ ├── jsp-api-2.0.jar
│ ├── jsr305-3.0.0.jar
│ ├── jtar-2.2.jar
│ ├── kryo-3.0.1.jar
│ ├── mail-1.4.7.jar
│ ├── metrics-json-3.1.0.jar
│ ├── metrics-jvm-3.1.0.jar
│ ├── mimepull-1.9.6.jar
│ ├── minlog-1.3.0.jar
│ ├── objenesis-2.1.jar
│ ├── osgi-resource-locator-1.0.1.jar
│ ├── reflectasm-1.10.1.jar
│ ├── reflections-0.9.9.jar
│ ├── selma-0.13.jar
│ ├── snakeyaml-1.12.jar
│ ├── snappy-0.4.jar
│ ├── stax2-api-3.1.4.jar
│ ├── streamsets-datacollector-common-2.2.0.0.jar
│ ├── streamsets-datacollector-container-2.2.0.0.jar
│ ├── streamsets-datacollector-container-common-2.2.0.0.jar
│ ├── streamsets-datacollector-json-dto-2.2.0.0.jar
│ ├── streamsets-datacollector-messaging-client-2.2.0.0.jar
│ ├── streamsets-sso-2.2.0.0.jar
│ ├── streamsets-utils-2.2.0.0.jar
│ ├── swagger-annotations-1.5.3.jar
│ ├── swagger-core-1.5.3.jar
│ ├── swagger-jaxrs-1.5.3.jar
│ ├── swagger-jersey2-jaxrs-1.5.3.jar
│ ├── swagger-models-1.5.3.jar
│ ├── validation-api-1.1.0.Final.jar
│ ├── websocket-api-9.2.17.v20160517.jar
│ ├── websocket-client-9.2.17.v20160517.jar
│ ├── websocket-common-9.2.17.v20160517.jar
│ ├── websocket-server-9.2.17.v20160517.jar
│ └── websocket-servlet-9.2.17.v20160517.jar
下面加载user和system stageLibs
这里是有白名单控制的:
在etc的sdc.properties中配置了黑白名单,注意黑白名单不能共存,一般配置黑名单,即从制定目录扫描到的全部libs中排除掉黑名单好了
#system.stagelibs.whitelist=system.stagelibs.blacklist=\ streamsets-datacollector-mapr_5_0-lib,\ streamsets-datacollector-mapr_5_1-lib,\ streamsets-datacollector-mapr_5_2-lib,\ streamsets-datacollector-apache-solr_6_1_0-lib##user.stagelibs.whitelist=#user.stagelibs.blacklist=
steamsets里面可以运行很多的pipeline,整个jvm其实是当作一个容器,那么containerClassLoader就负责整个容器的启动,相应的其它classloader的作用顾名思义
// Bootstrap container Thread.currentThread().setContextClassLoader(containerCL); Class klass = containerCL.loadClass(mainClass); Method method = klass.getMethod(SET_CONTEXT_METHOD, ClassLoader.class, ClassLoader.class, List.class, Instrumentation.class); method.invoke(null, apiCL, containerCL, stageLibrariesCLs, instrumentation); method = klass.getMethod(MAIN_METHOD, String[].class); method.invoke(null, new Object[]{new String[]{}});
apiCL, containerCL, stageLibrariesCLs这三个通过setContext方法完成初始化,传递给DataCollectorMain
不过,从执行方法看,
public static void setContext(ClassLoader apiCL, ClassLoader containerCL, List<? extends ClassLoader> moduleCLs, Instrumentation instrumentation) { MemoryUsageCollector.initialize(instrumentation); RuntimeModule.setStageLibraryClassLoaders(moduleCLs); }
似乎,apiClassLoader和containerClassLoader什么也没干,直接扔了
- streamsets Data Collecotor启动流程分析
- uboot 启动流程分析
- Uboot启动流程分析
- Bootloader启动流程分析
- Uboot启动流程分析
- activity 启动流程分析
- UBOOT启动流程分析
- Linux启动流程分析
- Uboot启动流程分析
- S3C2410启动流程分析
- Uboot启动流程分析
- Uboot启动流程分析
- 内核启动流程分析
- linux启动流程分析
- activity 启动流程分析
- android启动流程分析
- linux启动流程分析
- [Linux] 启动流程分析
- php实现下载
- java8实现spark streaming的wordcount
- android动态创建UI备忘
- 第16周项目1 验证算法(4)快速排序
- 第十四周项目1(1)--验证折半查找算法
- streamsets Data Collecotor启动流程分析
- 第15周项目3-B-树的基本操作
- Spring+Websocket实现消息的推送
- 51Nod-1534-棋子游戏
- 字符集导致的 error LNK2019: 无法解析的外部符号 "__declspec(dllimport)
- Putty打印时只有CR回车符时的问题
- Dynamic AX 快捷键
- 第16周项目1-归并排序
- (第十六周项目1)验证算法(6)堆排序