前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot开发spark-submit的java代码

springboot开发spark-submit的java代码

原创
作者头像
mikeLiu
修改2020-08-03 10:55:08
2.7K0
修改2020-08-03 10:55:08
举报
文章被收录于专栏:技术学习技术学习

springboot开发spark-submit的java代码

前言

习惯使用spark-submit提交python写的pyspark脚本,突然想开发基于springboot开发java spark代码。在实际开发工程中,由于对springboot不熟,遇到了很多问题,好在最终都解决了。以下记录了一些问题及其解决方法。

本文以统计日志中的累积用户和月活用户为例,进行说明:

  1. 工程代码
  2. 问题与解决

工程实现

开发环境

  1. spark 3.0.0 (生产环境 2.3.1)
  2. hadoop 3.2 (生产环境 2.6)
  3. IntelliJ IDEA Community Edition 2018.3.4 x64
  4. Maven 3.6.0
  5. java8
  6. 开发:windows 10, 运行:windows 10, linux

背景说明

**测试数据**

格式:parquet, schema信息如下:

代码语言:txt
复制
root

 |-- userid: string (nullable = true)

 |-- ts: integer (nullable = true)

数据样式:

代码语言:txt
复制
+----------------------------------------+----------+

|userid                                  |ts        |

+----------------------------------------+----------+

|6E26E7B94E52DC4AD9712320035F12784F54677A|1595116043|

|498AD603A26FCA20789DE46A69067AAB4F445535|1595139810|

|E64DA425FED067B0FA2717329E72169B4D545577|1595152077|

|D05ADF5CD7FD4134A6DF601A6A17D9C64E7A6B7A|1595119558|

|443DB7862123909484EAF84B0699E93F4F444D7A|1595143797|

+----------------------------------------+----------+

**实现目标**

统计日志中的累积用户和月活用户

**处理过程**:

将今日份的日活数据合入累积数据中,并对累积数据去重。若用户相同,保留时间最新的。

数据处理

完整工程代码见文章1

代码结构如下图:

  1. data目录存在测试数据;
  2. script脚本为linux下的spark-submit启动脚本;
  3. src目录为基于springboot的业务逻辑代码。其中,</br>

3.1 common包存在常量、分隔符;</br>

3.2 config包存在spark配置;</br>

3.3 entity包存在命令行参数,主要通过JobParamEntity进行参数共享;</br>

3.4 task目录实现所有的业务逻辑,其中DoPrepareTask组装输入输出目录,DoInitTask初始化SparkSession和UDF,DoProcessTask实现业务逻辑;</br>

3.5 udf包实现所有UDF;</br>

3.6 util包存放常用工具类。

代码语言:txt
复制
├─data

│  ├─input

│  │  └─20200719

│  └─output

│      ├─month

│      │  └─20200719

│      └─total

│          ├─20200718

│          └─20200719

├─script

├─src

   ├─main

   │  ├─java

   │  │  └─com

   │  │      └─demo

   │  │          └─sparksubmit

   │  │              ├─common

   │  │              ├─config

   │  │              ├─entity

   │  │              ├─task

   │  │              ├─udf

   │  │              └─util

   │  └─resources

   └─test

       └─java

           └─com

               └─demo

                   └─sparksubmit

问题与解决

调试报错

**报错1: java.lang.ClassNotFoundException:org.apache.spark.sql.SparkSession** </br>

解决:本地调试时,需要引入spark相关的依赖,且不能为provided

代码语言:txt
复制
<dependency>

    <groupId>org.apache.spark</groupId>

    <artifactId>spark-core\_${scale.version}</artifactId>

    <version>${spark.version}</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\_${scale.version}</artifactId>

    <version>${spark.version}</version>

    <!--调试时注解,打包时添加-->

    <!--<scope>provided</scope>-->

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-hive -->

<dependency>

    <groupId>org.apache.spark</groupId>

    <artifactId>spark-hive\_${scale.version}</artifactId>

    <version>${spark.version}</version>

    <!--调试时注解,打包时添加-->

    <!--<scope>provided</scope>-->

</dependency>
打包报错

**报错1:A master URL must be set in your configuration**</br>

在本地测试时,设置master为local模式,但是在打成jar时,需要将其注解

代码语言:txt
复制
SparkSession spark = SparkSession.builder()

        //.master("local[\*]")

        .appName("spark-submit-demo")

        .enableHiveSupport()

        .getOrCreate();

但是在打包时一直出现上述报错信息,文章2说是SparkSession在driver的main函数外初始化导致代码无法分发。经尝试调试SparkSession代码也没能解决这个问题。后来从打包的日志中,发现运行了spark代码。经排查发现是执行springbootTest时因未master而报错。注解掉即可解决问题:

代码语言:txt
复制
// SpringBootTest会执行代码,若未设置master会报错

//@SpringBootTest

class GetidApplicationTests {



    @Test

    void contextLoads() {

    }



}

**报错2:com.google.gson.GsonBuilder.setLenient 或者 compatible version of com.google.gson.GsonBuilder** </br>

文章3指出为gson的版本太低,引入新版本即可解决这个问题,遗憾的是未能解决问题。

代码语言:txt
复制
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->

<dependency>

   <groupId>com.google.code.gson</groupId>

   <artifactId>gson</artifactId>

   <!--此时的最新版本-->

   <version>2.8.6</version>

</dependency>

文章4中指出是在运行时,Spark的gson包覆盖了新版本,需要在配置启动参数userClassPathFirst,遗憾的是未能解决问题。

代码语言:txt
复制
${SPARK\_SUBMIT} \

--conf spark.executor.userClassPathFirst=true\

--conf spark.driver.userClassPathFirst=true \

...

文章5指出由于springboot自动加载配置导致加载spark的gson出错,可以通过exclude加载解决。问题终于得以解决。

代码语言:txt
复制
//(exclude = {GsonAutoConfiguration.class})

@SpringBootApplication(exclude = {GsonAutoConfiguration.class})

**报错3: No auto configuration classes found in META-INF/spring.factories 或者 java.lang.ClassCastException: cannot assign instance of scala.collection.immutable.List**</br>

这个主要是打包方式不同,导致错误不同,仅第3种方式可正常运行

  1. spring-boot-maven-plugin 打包插件: 将provided内容打入jar包中,导致错误
代码语言:txt
复制
<!--可打包,可本地spark-submit, 但是不能在集群中运行-->

<plugin>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-maven-plugin</artifactId>

    <configuration>

        <fork>true</fork>

        <mainClass>${start-class}</mainClass>

        <excludes>

            <exclude>

                <groupId>org.apache.spark</groupId>

                <artifactId>spark-core\_${scale.version}</artifactId>

            </exclude>

            <exclude>

                <groupId>org.apache.spark</groupId>

                <artifactId>spark-sql\_${scale.version}</artifactId>

            </exclude>

            <exclude>

                <groupId>org.apache.spark</groupId>

                <artifactId>spark-hive\_${scale.version}</artifactId>

            </exclude>

        </excludes>

    </configuration>

    <executions>

        <execution>

            <goals>

                <goal>repackage</goal>

            </goals>

        </execution>

    </executions>

</plugin>
  1. maven-compiler-plugin,maven-assembly-plugin:本地spark-submit找不到主类
代码语言:txt
复制
<!--可打包,本地运行报错:找不到主类-->

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-compiler-plugin</artifactId>

    <version>2.4</version>

    <configuration>

        <source>1.8</source>

        <target>1.8</target>

        <encoding>UTF-8</encoding>

    </configuration>

</plugin>

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-assembly-plugin</artifactId>

    <version>2.4</version>

    <configuration>

        <archive>

            <manifest>

                <addClasspath>true</addClasspath>

                <mainClass>${start-class}</mainClass>

            </manifest>

        </archive>

        <descriptorRefs>

            <descriptorRef>jar-with-dependencies</descriptorRef>

        </descriptorRefs>

    </configuration>

    <executions>

        <execution>

            <id>make-assembly</id>

            <phase>package</phase>

            <goals>

                <goal>single</goal>

            </goals>

        </execution>

    </executions>

</plugin>
  1. maven-shade-plugin 可以正常打包,正常运行 </br>

本章6指出springboot 打spark-submit包的正确方式

代码语言:txt
复制
<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-shade-plugin</artifactId>

    <version>2.3</version>

<executions>

    <execution>

        <phase>package</phase>

        <goals>

            <goal>shade</goal>

        </goals>

        <configuration>

            <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>

            <createDependencyReducedPom>false</createDependencyReducedPom>

            <filters>

                <filter>

                    <artifact>\*:\*</artifact>

                    <excludes>

                        <exclude>META-INF/\*.SF</exclude>

                        <exclude>META-INF/\*.DSA</exclude>

                        <exclude>META-INF/\*.RSA</exclude>

                    </excludes>

                </filter>

            </filters>

            <transformers>

                <transforme

                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                    <resource>META-INF/spring.handlers</resource>

                </transformer>

                <transforme

                        implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">

                    <resource>META-INF/spring.factories</resource>

                </transformer>

                <transforme

                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                    <resource>META-INF/spring.schemas</resource>

                </transformer>

                <transforme

                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>

                <transforme

                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                    <mainClass>${start-class}</mainClass>

                </transformer>

            </transformers>

        </configuration>

    </execution>

</executions>

</plugin>

小结

由于对springboot的不了解,只能去一一解决表象问题,抓不到本质,后续还需更加努力。

****

参考文献

1 工程代码https://github.com/Lmikic101/sparksubmit_demo</br>

2 Spark异常:A master URL must be set in your configuration处理记录,https://www.cnblogs.com/ldsggv/p/9258865.html </br>

3 An attempt was made to call the method com.google.gson.GsonBuilder.setLenient https://blog.csdn.net/qq_35387940/article/details/89098208</br>

4 spark程序jar与spark lib jar冲突,加载顺序,https://www.jianshu.com/p/0fe48bc43a8c</br>

5 Why do I get Gson builder error when starting a Spring Boot application?, https://stackoverflow.com/questions/50031381/why-do-i-get-gson-builder-error-when-starting-a-spring-boot-application </br>

6 spark submit spring boot application, https://blog.csdn.net/hzs33/article/details/83183217

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • springboot开发spark-submit的java代码
    • 前言
      • 工程实现
        • 开发环境
        • 背景说明
        • 数据处理
        • 问题与解决
      • 小结
        • 参考文献
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档