运行 非默认类加载器下的本地集群
Run a local cluster under a nondefault classloader
来自网络的本地集群 classloader
我正在尝试从 Web 容器 运行 本地集群(是的,它仅用于开发和测试目的)并且在使用 classloader 时遇到困难。
直接方法
当我以简单且 recommended 的方式做到时,
ILocalCluster localCluster = new LocalCluster();
localCluster.submitTopology(topologyName, stormConf, topology);
我得到奖励
Async loop died!: java.lang.ClassCastException: my.company.storm.bolt.SomeFilteringBolt cannot be cast to org.apache.storm.task.IBolt
at org.apache.storm.daemon.executor$fn__7953$fn__7966.invoke(executor.clj:787)
at org.apache.storm.util$async_loop$fn__625.invoke(util.clj:482)
at clojure.lang.AFn.run(AFn.java:22)
at java.lang.Thread.run(Thread.java:745)
这是因为用于加载和实例化 StormTopology
的 classloader 是 Jetty WebAppClassLoader
的实例,但是 [=17= 产生的(子)进程] 显然使用系统 classloader。我通过在 SomeFilteringBolt
的静态块中记录 classloader 来确认这一点 - class 确实被加载了两次并且来自 WebAppCL 的螺栓显然不能转换为系统上的螺栓 class加载程序稍后。
预期行为
现在,这让我感到惊讶,因为我认为 Storm 会序列化 StormTopology
实例,"send" 在本地,反序列化它并 运行 它。但是,如果这样做,它肯定会起作用。相反,它似乎直接使用提供的 StormTopology
实例,这在不同的 classloader 下是有问题的。
自从
以来我尝试过的
我尝试将它们设置为 true
以强制 Storm 在本地序列化我的拓扑。没有变化。
我试过运行在系统classloader:
下安装LocalCluster
ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
Config topologyConf = createTopologyConfig();
Map<String, Object> stormConf = createStormConfig(topologyConf);
StormTopology topology = createTopology(topologyConf);
ILocalCluster localCluster = new LocalCluster();
localCluster.submitTopology(topologyName, stormConf, topology);
} finally {
Thread.currentThread().setContextClassLoader(originalClassloader);
}
这实际上让我更进一步:
Thread died: java.lang.ExceptionInInitializerError
at clojure.core__init.__init0(Unknown Source)
at clojure.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2154)
at clojure.lang.RT.classForName(RT.java:2163)
at clojure.lang.RT.loadClassForName(RT.java:2182)
at clojure.lang.RT.load(RT.java:436)
at clojure.lang.RT.load(RT.java:412)
at clojure.lang.RT.doInit(RT.java:454)
at clojure.lang.RT.<clinit>(RT.java:330)
at clojure.lang.Namespace.<init>(Namespace.java:34)
at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
at clojure.lang.Var.internPrivate(Var.java:151)
at org.apache.storm.LocalCluster.<clinit>(Unknown Source)
at my.company.storm.LocalTopologyRunner.startTopology(LocalTopologyRunner.java:146)
... 10 more
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/refer
at clojure.lang.Var$Unbound.throwArity(Var.java:43)
at clojure.lang.AFn.invoke(AFn.java:32)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.RT.doInit(RT.java:467)
at clojure.lang.RT.<clinit>(RT.java:330)
... 18 more
哇?!
问题
如何从系统 classloader 以外的 classloader 安全地 运行 本地模式下的 Storm 拓扑?
我运行正在使用 Apache Storm 1.0.1,Jetty 8.1,Java 8u112 x64,Windows 7 x64。
根本不是 Storm 专家,但这让我想起了我过去遇到的一个老 "identity crisis" 问题。
尝试两件事:
通过调用 org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(true)
将优先级设置为系统 class 加载程序
如果不起作用,您可以调用方法org.eclipse.jetty.webapp.WebAppContext.setSystemClasses
或org.eclipse.jetty.webapp.WebAppContext.addSystemClass
来控制哪些class被认为是系统class es 在 webapp 域内。
在加载它们之前(在 webapp 初始化期间)为整个 storm 包执行此操作(它允许像 "org.apache.storm." 这样的通配符)。
值得一试!祝你好运。
Apache Storm 1.0.3 神奇地修复了这个问题。
即使没有 TOPOLOGY_TESTING_ALWAYS_TRY_SERIALIZE
,即使发行说明中没有修复的痕迹,所以我无法追踪到代码更改。无论如何,我们很高兴它现在按预期工作。
来自网络的本地集群 classloader
我正在尝试从 Web 容器 运行 本地集群(是的,它仅用于开发和测试目的)并且在使用 classloader 时遇到困难。
直接方法
当我以简单且 recommended 的方式做到时,
ILocalCluster localCluster = new LocalCluster();
localCluster.submitTopology(topologyName, stormConf, topology);
我得到奖励
Async loop died!: java.lang.ClassCastException: my.company.storm.bolt.SomeFilteringBolt cannot be cast to org.apache.storm.task.IBolt
at org.apache.storm.daemon.executor$fn__7953$fn__7966.invoke(executor.clj:787)
at org.apache.storm.util$async_loop$fn__625.invoke(util.clj:482)
at clojure.lang.AFn.run(AFn.java:22)
at java.lang.Thread.run(Thread.java:745)
这是因为用于加载和实例化 StormTopology
的 classloader 是 Jetty WebAppClassLoader
的实例,但是 [=17= 产生的(子)进程] 显然使用系统 classloader。我通过在 SomeFilteringBolt
的静态块中记录 classloader 来确认这一点 - class 确实被加载了两次并且来自 WebAppCL 的螺栓显然不能转换为系统上的螺栓 class加载程序稍后。
预期行为
现在,这让我感到惊讶,因为我认为 Storm 会序列化 StormTopology
实例,"send" 在本地,反序列化它并 运行 它。但是,如果这样做,它肯定会起作用。相反,它似乎直接使用提供的 StormTopology
实例,这在不同的 classloader 下是有问题的。
自从
以来我尝试过的我尝试将它们设置为 true
以强制 Storm 在本地序列化我的拓扑。没有变化。
我试过运行在系统classloader:
下安装LocalClusterClassLoader originalClassloader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
Config topologyConf = createTopologyConfig();
Map<String, Object> stormConf = createStormConfig(topologyConf);
StormTopology topology = createTopology(topologyConf);
ILocalCluster localCluster = new LocalCluster();
localCluster.submitTopology(topologyName, stormConf, topology);
} finally {
Thread.currentThread().setContextClassLoader(originalClassloader);
}
这实际上让我更进一步:
Thread died: java.lang.ExceptionInInitializerError
at clojure.core__init.__init0(Unknown Source)
at clojure.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2154)
at clojure.lang.RT.classForName(RT.java:2163)
at clojure.lang.RT.loadClassForName(RT.java:2182)
at clojure.lang.RT.load(RT.java:436)
at clojure.lang.RT.load(RT.java:412)
at clojure.lang.RT.doInit(RT.java:454)
at clojure.lang.RT.<clinit>(RT.java:330)
at clojure.lang.Namespace.<init>(Namespace.java:34)
at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
at clojure.lang.Var.internPrivate(Var.java:151)
at org.apache.storm.LocalCluster.<clinit>(Unknown Source)
at my.company.storm.LocalTopologyRunner.startTopology(LocalTopologyRunner.java:146)
... 10 more
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/refer
at clojure.lang.Var$Unbound.throwArity(Var.java:43)
at clojure.lang.AFn.invoke(AFn.java:32)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.RT.doInit(RT.java:467)
at clojure.lang.RT.<clinit>(RT.java:330)
... 18 more
哇?!
问题
如何从系统 classloader 以外的 classloader 安全地 运行 本地模式下的 Storm 拓扑?
我运行正在使用 Apache Storm 1.0.1,Jetty 8.1,Java 8u112 x64,Windows 7 x64。
根本不是 Storm 专家,但这让我想起了我过去遇到的一个老 "identity crisis" 问题。
尝试两件事:
通过调用
org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(true)
将优先级设置为系统 class 加载程序
如果不起作用,您可以调用方法
org.eclipse.jetty.webapp.WebAppContext.setSystemClasses
或org.eclipse.jetty.webapp.WebAppContext.addSystemClass
来控制哪些class被认为是系统class es 在 webapp 域内。
在加载它们之前(在 webapp 初始化期间)为整个 storm 包执行此操作(它允许像 "org.apache.storm." 这样的通配符)。
值得一试!祝你好运。
Apache Storm 1.0.3 神奇地修复了这个问题。
即使没有 TOPOLOGY_TESTING_ALWAYS_TRY_SERIALIZE
,即使发行说明中没有修复的痕迹,所以我无法追踪到代码更改。无论如何,我们很高兴它现在按预期工作。