【问题标题】:Unable to submit Spring boot java application to Spark cluster无法将 Spring Boot Java 应用程序提交到 Spark 集群
【发布时间】:2015-10-06 13:43:49
【问题描述】:

我使用 Spring Boot 开发了一个 Web 应用程序,它使用 Apache Spark 来查询来自不同数据源(如 Oracle)的数据。一开始,我计划使用 spark-submit 脚本不提交应用程序就运行应用程序,但看起来如果不提交 jar 就无法连接到 Master 集群。我已经成功生成了一个 uber jar,其中包含我正在使用的所有依赖项和子项目,但似乎 Spark 不喜欢 Spring Boot 应用程序。当我尝试提交应用程序时,spark 显示以下错误:

Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Log4jLoggerFactory loaded from file:/home/rojasmi1/spark/spark-1.4.0/assembly/target/scala-2.10/spark-assembly-1.4.0-hadoop2.2.0.jar). If you are using Weblogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml Object of class [org.slf4j.impl.Log4jLoggerFactory] must be an instance of class ch.qos.logback.classic.LoggerContext
at org.springframework.util.Assert.isInstanceOf(Assert.java:339)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:151)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLogger(LogbackLoggingSystem.java:143)
at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:89)
at org.springframework.boot.logging.LoggingApplicationListener.onApplicationStartedEvent(LoggingApplicationListener.java:152)
at org.springframework.boot.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
at org.springframework.boot.context.event.EventPublishingRunListener.publishEvent(EventPublishingRunListener.java:100)
at org.springframework.boot.context.event.EventPublishingRunListener.started(EventPublishingRunListener.java:54)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:277)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at ch.dlx.QubidaOracleConnectorApplication.main(QubidaOracleConnectorApplication.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:664)
at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:169)
at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:192)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:111)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

使用 Spark 的默认 log4j 配置文件:org/apache/spark/log4j-defaults.properties

我尝试在 pom 文件中排除 slf4j-log4j12 依赖项,但仍然遇到同样的错误。

pom文件包含以下配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>ch.dlx</groupId>
<artifactId>qubida-oracle-connector</artifactId>
<version>0.0.1-SNAPSHOT</version>

<name>qubida-oracle-connector</name>
<description></description>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
            </exclusion>

        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- Spark -->

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.11</artifactId>
        <version>1.4.0</version>
        <scope>provided</scope>
        <exclusions>
                    <exclusion>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_2.11</artifactId>
        <version>1.4.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-hadoop-core</artifactId>
        <version>1.3.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- DB Drivers -->

    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>10.2.0.4.0</version>
    </dependency>


</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
                <keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>

                <artifactSet>
                    <excludes>
                        <exclude>org.slf4j</exclude>
                    </excludes>
                </artifactSet>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

有没有办法将 Spring Boot 应用程序提交到集群?考虑到我需要公开 RESTful API,我应该使用其他类型的项目吗? 有没有办法在不提交 .jar 的情况下连接到 spark 集群?

提前感谢您的帮助。

【问题讨论】:

    标签: java jar apache-spark spring-boot


    【解决方案1】:

    在构建时,Spring Boot 会查看您是否在构建中包含了特定的日志记录实现,如果没有,则默认使用 Logback。显然,Spark 在运行您的应用程序时将 Log4J 添加到类路径中,这反过来又会导致运行时错误,因为 Spring Boot 现在在类路径上找到了两个记录器实现:一个在构建时包含(Logback),一个 Spark 是在运行时添加 (Log4J)。

    如果 Spark 提供了一种在运行时禁止包含 Log4J 的方法,您可以这样做,并且默认情况下让 Spring Boot 连接到 Logback。

    如果 Spark 对您强制使用 Log4J,那么解决方案是在您的构建中明确包含 Log4J(而不是 Logback),以便 Spring Boot 将“看到”它的构建时间,因此不包含 Logback。

    编辑:我应该通过查看 Spring Boot 文档来检查我的假设。您还必须明确排除 Log4J。见Spring Boot's Logging Docs

    【讨论】:

    • 亲爱的 RichW。我遵循了您建议的第二种方法(如果 Spark 强制您使用 Log4J,那么解决方案是在您的构建中明确包含 Log4J(而不是 Logback),以便 Spring Boot 将“看到”它的构建时间,因此不包含Logback),但不幸的是问题仍然存在。这就是我明确添加 Log4j 依赖的方式:&lt;dependency&gt; &lt;groupId&gt;log4j&lt;/groupId&gt; &lt;artifactId&gt;log4j&lt;/artifactId&gt; &lt;/dependency&gt; 你知道我还能尝试什么吗?
    • 对不起,斯特凡,我搞砸了。我编辑了我的答案。
    【解决方案2】:

    我遇到了类似的问题,为了解决它,请尝试使用以下排除项删除 Spring Boot 日志记录:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    

    如果在初始化 servlet 时仍然出现错误

    java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;

    然后尝试使用 starter parent 的 1.2.1.RELEASE 版本,因为这是由于 Spark Cluster 使用的 servlet-api 版本造成的。

    【讨论】:

    • 这正是我的问题的解决方案。嗨 5!
    【解决方案3】:

    Spark 仅支持 log4j。为了强制 spring-boot 默认使用 log4j 而不是 logback,应用 this procedure from spring-boot reference documentation 但确保将 log4j2 更改为 log4j 并给它一个版本,例如1.2.17。 您还需要将 log4j.properties 文件放入src/main/resources。您可以从 Spark 的 /conf 目录中复制 log4j.properties.template 并将其重命名为 log4j.properties。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      相关资源
      最近更新 更多