【问题标题】:Multiple Spark servers in a single JVM单个 JVM 中的多个 Spark 服务器
【发布时间】:2017-01-03 20:52:27
【问题描述】:

有没有办法在同一个 JVM 中运行多个 Sparkjava 服务器实例?我在“插件”软件中使用它,根据外部情况,我的插件的多个实例可能会启动,然后导致

java.lang.IllegalStateException: This must be done before route mapping has begun
at spark.SparkBase.throwBeforeRouteMappingException(SparkBase.java:256)
at spark.SparkBase.port(SparkBase.java:101)
at com.foo.bar.a(SourceFile:59)

在我看来,它是围绕代码中的静态字段大量构建的代码,所以我正在考虑一个类加载器技巧或使用SparkServerFactory 以某种方式消除SparkBase

【问题讨论】:

  • 可能这些实例使用相同的端口号。当您启动 spark 实例时,它必须在自己的端口上运行
  • 不,当您尝试初始化第二个端口时会发生这种情况,无论端口是否相同。第一次初始化将标志设置为 true,从那时起,大多数配置方法都被锁定。
  • 我在使用 sparkjava 运行集成测试时遇到了同样的问题。作为一种解决方法,请确保为 maven 故障安全插件设置 forkCount=1/reuseForks=false 以在其自己的 JVM 进程中执行每个测试类(请参阅maven.apache.org/surefire/maven-surefire-plugin/examples/…

标签: java spark-java


【解决方案1】:

从 Spark 2.5 你可以使用ignite():

http://sparkjava.com/news.html#spark25released

例子:

public static void main(String[] args) {
    igniteFirstSpark();
    igniteSecondSpark();
}

static void igniteSecondSpark() {
    Service http = ignite();

    http.get("/basicHello", (q, a) -> "Hello from port 4567!");
}

static void igniteFirstSpark() {
    Service http = ignite()
                      .port(8080)
                      .threadPool(20);

    http.get("/configuredHello", (q, a) -> "Hello from port 8080!");
}

我个人将它们初始化如下:

import spark.Service

public static void main(String[] args) {
    Service service1 = Service.ignite().port(8080).threadPool(20)
    Service service2 = Service.ignite().port(8081).threadPool(10)
}

我建议阅读how to use those services outside your main method,我认为这在这里很有用。

【讨论】:

  • 有没有办法让它们都在一个端口上运行?
  • 我看到的一个解决方案是重用服务实例
【解决方案2】:

技巧是忽略在spark.Spark 中实现的围绕Spark 的外部静态shell,直接使用内部spark.webserver.SparkServer。代码中有一些需要解决的问题,例如spark.webserver.JettyHandler 不是公开的,所以你不能从你的代码中实例化它,但你可以通过将你自己的类放入该包中来扩展它并将其公开。

所以解决方案是这样的:

SimpleRouteMatcher routeMatcher1 = new SimpleRouteMatcher();
routeMatcher1.parseValidateAddRoute("get '/foo'", "*/*", wrap("/foo", "*/*", (req, res) -> "Hello World 1"));

MatcherFilter matcherFilter1 = new MatcherFilter(routeMatcher1, false, false);
matcherFilter1.init(null);
PublicJettyHandler handler1 = new PublicJettyHandler(matcherFilter1);
SparkServer server1 = new SparkServer(handler1);

new Thread(() -> {
            server1.ignite("0.0.0.0", 4567, null, null, null, null, "/META-INF/resources/", null, new CountDownLatch(1),
                    -1, -1, -1);
        }).start();

并且需要在你的代码库中复制 wrap 方法:

protected RouteImpl wrap(final String path, String acceptType, final Route route) {
        if (acceptType == null) {
            acceptType = "*/*";
        }
        RouteImpl impl = new RouteImpl(path, acceptType) {
            @Override
            public Object handle(Request request, Response response) throws Exception {
                return route.handle(request, response);
            }
        };
        return impl;
    }

如果您的应用中需要多个 Spark 服务器,这似乎是一种可行的解决方法。

【讨论】:

    【解决方案3】:

    我在使用 Spark 运行单元测试时遇到了这个问题,为了解决这个问题,我修改了 pom.xml 文件。

    forkCount=1 reuseForks=false

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire.version}</version>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>${junit.platform.version}</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <forkCount>1</forkCount>
                    <reuseForks>false</reuseForks>
    

    【讨论】:

    • 我无法让您的建议按原样工作 - 我得到“目标 org.apache.maven.plugins:maven-surefire-plugin:2.22.0:test 的执行默认测试失败: java.lang.ClassNotFoundException”。但是删除“依赖项”部分后它可以工作。谢谢
    猜你喜欢
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 2019-03-13
    • 1970-01-01
    相关资源
    最近更新 更多