1

I use springboot and storm to do a demo,it works in local mode,but report an error in cluster mode when i submit a jar

./storm jar storm-demo3-0.0.1-SNAPSHOT.jar org.springframework.boot.loader.JarLauncher simpleBoot

When i romove the springBoot and package with maven-compiler-plugin then it can work well

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

this is the error on supervisor

java.lang.RuntimeException: java.lang.ClassNotFoundException: com.fosung.share.stormdemo3.bolt.FilterBolt
        at org.apache.storm.utils.Utils.javaDeserialize(Utils.java:259) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.utils.Utils.getSetComponentObject(Utils.java:507) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.task$get_task_object.invoke(task.clj:76) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.task$mk_task_data$fn__6524.invoke(task.clj:180) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.util$assoc_apply_self.invoke(util.clj:931) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.task$mk_task_data.invoke(task.clj:172) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.task$mk_task.invoke(task.clj:184) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.executor$mk_executor$fn__10662.invoke(executor.clj:379) ~[storm-core-1.2.2.jar:1.2.2]
        at clojure.core$map$fn__4553.invoke(core.clj:2622) ~[clojure-1.7.0.jar:?]
        at clojure.lang.LazySeq.sval(LazySeq.java:40) ~[clojure-1.7.0.jar:?]
        at clojure.lang.LazySeq.seq(LazySeq.java:49) ~[clojure-1.7.0.jar:?]
        at clojure.lang.RT.seq(RT.java:507) ~[clojure-1.7.0.jar:?]
        at clojure.core$seq__4128.invoke(core.clj:137) ~[clojure-1.7.0.jar:?]
        at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30) ~[clojure-1.7.0.jar:?]
        at clojure.core.protocols$fn__6506.invoke(protocols.clj:101) ~[clojure-1.7.0.jar:?]
        at clojure.core.protocols$fn__6452$G__6447__6465.invoke(protocols.clj:13) ~[clojure-1.7.0.jar:?]
        at clojure.core$reduce.invoke(core.clj:6519) ~[clojure-1.7.0.jar:?]
        at clojure.core$into.invoke(core.clj:6600) ~[clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.executor$mk_executor.invoke(executor.clj:380) ~[storm-core-1.2.2.jar:1.2.2]
        at org.apache.storm.daemon.worker$fn__11300$exec_fn__2470__auto__$reify__11302$iter__11307__11311$fn__11312.invoke(worker.clj:663) ~[storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.LazySeq.sval(LazySeq.java:40) ~[clojure-1.7.0.jar:?]
        at clojure.lang.LazySeq.seq(LazySeq.java:49) ~[clojure-1.7.0.jar:?]
        at clojure.lang.RT.seq(RT.java:507) ~[clojure-1.7.0.jar:?]
        at clojure.core$seq__4128.invoke(core.clj:137) ~[clojure-1.7.0.jar:?]
        at clojure.core$dorun.invoke(core.clj:3009) ~[clojure-1.7.0.jar:?]
        at clojure.core$doall.invoke(core.clj:3025) ~[clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker$fn__11300$exec_fn__2470__auto__$reify__11302.run(worker.clj:663) ~[storm-core-1.2.2.jar:1.2.2]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_152]
        at javax.security.auth.Subject.doAs(Subject.java:422) ~[?:1.8.0_152]
        at org.apache.storm.daemon.worker$fn__11300$exec_fn__2470__auto____11301.invoke(worker.clj:633) ~[storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.AFn.applyToHelper(AFn.java:178) ~[clojure-1.7.0.jar:?]
        at clojure.lang.AFn.applyTo(AFn.java:144) ~[clojure-1.7.0.jar:?]
        at clojure.core$apply.invoke(core.clj:630) ~[clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker$fn__11300$mk_worker__11391.doInvoke(worker.clj:605) [storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.RestFn.invoke(RestFn.java:512) [clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker$_main.invoke(worker.clj:798) [storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.AFn.applyToHelper(AFn.java:165) [clojure-1.7.0.jar:?]
        at clojure.lang.AFn.applyTo(AFn.java:144) [clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker.main(Unknown Source) [storm-core-1.2.2.jar:1.2.2]
Caused by: java.lang.ClassNotFoundException: com.fosung.share.stormdemo3.bolt.FilterBolt
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[?:1.8.0_152]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_152]
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[?:1.8.0_152]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_152]
        at java.lang.Class.forName0(Native Method) ~[?:1.8.0_152]
        at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:683) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1863) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568) ~[?:1.8.0_152]
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428) ~[?:1.8.0_152]
        at org.apache.storm.utils.Utils.javaDeserialize(Utils.java:253) ~[storm-core-1.2.2.jar:1.2.2]
        ... 38 more
2019-05-22 11:09:14.684 o.a.s.util main [ERROR] Halting process: ("Error on initialization")
java.lang.RuntimeException: ("Error on initialization")
        at org.apache.storm.util$exit_process_BANG_.doInvoke(util.clj:341) [storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.RestFn.invoke(RestFn.java:423) [clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker$fn__11300$mk_worker__11391.doInvoke(worker.clj:605) [storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.RestFn.invoke(RestFn.java:512) [clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker$_main.invoke(worker.clj:798) [storm-core-1.2.2.jar:1.2.2]
        at clojure.lang.AFn.applyToHelper(AFn.java:165) [clojure-1.7.0.jar:?]
        at clojure.lang.AFn.applyTo(AFn.java:144) [clojure-1.7.0.jar:?]
        at org.apache.storm.daemon.worker.main(Unknown Source) [storm-core-1.2.2.jar:1.2.2]

my pom.xml

<properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.storm</groupId>
            <artifactId>storm-core</artifactId>
            <version>1.2.2</version>
            <!--<scope>provided</scope>-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-slf4j-impl</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-1.2-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-web</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <artifactId>ring-cors</artifactId>
                    <groupId>ring-cors</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

MyTopology

public class MyTopology {


    public  static void main(String[] args) {
        System.out.println("MyTopology main start");
        // 定义一个拓扑

        TopologyBuilder builder = new TopologyBuilder();
        // 设置1个Executeor(线程),默认一个
        DataSpout dataSpout = new DataSpout();
        builder.setSpout("spoutId", dataSpout);
        // shuffleGrouping:表示是随机分组
        // 设置1个Executeor(线程),和两个task
        FilterBolt filterBolt = new FilterBolt();
        InsertBolt insertBolt = new InsertBolt();

        builder.setBolt("filterBolt", filterBolt).setNumTasks(1).allGrouping("spoutId", "spoutId");
        builder.setBolt("insertBolt", insertBolt).setNumTasks(1).allGrouping("filterBolt", "spoutId");
        Config conf = new Config();

        try {
            // 有参数时,表示向集群提交作业,并把第一个参数当做topology名称
            // 没有参数时,本地提交
            if (args != null && args.length > 0) {
                System.out.println("运行远程模式");
                StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
            } else {
                // 启动本地模式
                System.out.println("运行本地模式");
                LocalCluster cluster = new LocalCluster();
                cluster.submitTopology("TopologyApp", conf, builder.createTopology());
            }
        } catch (Exception e) {
            System.out.println("storm启动失败!程序退出!");
            System.exit(1);
            e.printStackTrace();
        }
//        System.out.println("storm启动成功...");
    }
}

My spout

public class DataSpout extends BaseRichSpout {

    SpoutOutputCollector collector;

    @Override
    public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
        this.collector = collector;
        System.out.println("spout open");
    }

    @Override
    public void nextTuple() {
        /*try {
            Thread.sleep(1000);
            return;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        System.out.println("spout nextTuple start");
        int rndomn = (int)Math.random() * 1000;

        collector.emit("spoutId", new Values(rndomn));

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declareStream("spoutId", new Fields("spoutId"));
    }
}

My bolt


public class FilterBolt extends BaseRichBolt  {
    OutputCollector collector;
    @Override
    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
        this.collector = collector;
    }

    @Override
    public void execute(Tuple input) {
        System.out.println("filter bolt start");
        Integer o = (Integer) input.getValues().get(0);
        if (o>10){
            collector.emit("spoutId", new Values(o));
        }

    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {

        //定义下个bolt接收streamId
        declarer.declareStream("spoutId", new Fields("spoutId"));

    }
}
qxs
  • 11
  • 1

1 Answers1

0

Spring (boot) doesn't fit nicely with Storm. Storm is a framework, meaning it is responsible for managing the lifecycle of some classes like your bolt. As Storm doesn't know anything about Spring, Spring's dependency injection doesn't work out of the box. It is possible to set up Spring to work on parts of a Storm application with e.g. task and worker hooks, which can allow you to create a Spring context in a Storm worker. I don't think I would recommend it unless you have a good reason to need Spring.

Regarding the error you're getting, Storm is failing to find one of your classes in the jar you're submitting. Since you didn't post your pom.xml for your Spring configuration, it's hard to tell, but maybe you're using a plugin that moves your classes around. When you submit a topology to Storm, Storm runs a couple of phases you should understand:

First you do storm jar com.yourcompany.yourMain. This starts a JVM on your local machine (or wherever you're running the command), which runs your topology setup, in your case MyTopology.main. The setup then serializes your spouts and bolts, and sends the jar and serialized topology to Nimbus (a separate JVM), which in turn sends it to the supervisors (yet another separate JVM). On the supervisors, the supervisor JVM boots up a number of worker JVMs to run your topology. Each worker JVM starts with a command like java -cp your-topology.jar org.apache.storm.Worker. The worker JVMs load the serialized topology, and the classes in your topology jar, and boot up threads to run your spouts and bolts.

These phases are most likely the reason it's failing for you. When you run the topology setup code, you're doing it with a Spring Boot command, so Spring Boot gets a chance to run. When the topology starts up on the worker machines, the JVMs are started with a regular old call to a non-Spring main method, so Spring doesn't get a chance to run.

If you decide not to use Spring, you can find a working example POM here.

Other links that may be of interest are an earlier answer and a project doing Spring integration for Storm.

Stig Rohde Døssing
  • 3,621
  • 2
  • 7
  • 7