spark之SparkCore代码入门02

1. Spark项目的创建

​ 说明一点,这里创建的项目,比之前稍微复杂一点点–基于maven的聚合和继承项目。
创建父工程,再创建多个子模块,这里用到spark-core
因为我不想再重新截图,所以用之前的,模块名会不完全相同,但都是一个意思,但能看懂
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:父模块,一般不做开发,也就可以删除src相关目录;主要的作用就是用来管理所有的子模块,管理整个项目中使用到的依赖及其版本。
在这里插入图片描述
创建子目录–通用common
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 项目编码

1. 添加模块为scala项目

第一步,在src下面创建一个scala目录,用于编写scala代码,并且将scala的目录指定为source root
在这里插入图片描述
发现无法直接创建scala的class
在这里插入图片描述
修改project structure,添加scala模块到core中
在这里插入图片描述

给core模块添加
在这里插入图片描述

2. 本地编码运行

需要注意的是,入口类为SparkContext。

不同版本有不同的SparkContext,java版本的是JavaSparkContext,scala的版本就是SparkContext;SparkSQL的入口有SessionContext;SparkStreaming的入口又是StreamingContext。

加载本地数据"C:\Users\70201\Desktop\wordcount.txt"
加载hdfs数据"hdfs://hadoop003:9000/data/spark/hello.txt"

master: 代表的spark作业运行的方式,常见的运行方式有local模式、standalone模式、yarn模式
local模式的写法: spark作业在本地来进行运行,没有提交到集群中去
    local       :为当前spark作业分配一个工作线程
    local[N]    :为当前spark作业分配N个工作线程,但是不能超过电脑可用个工作线程
    local[*]    :为当前spark作业分配可用个工作线程
    local[R, N] :为当前spark作业分配N个工作线程,如果提交作业失败,会进行最多R次的重试
standalone模式的写法
    普通的分布式:spark://<ip>:<port>
    ha   :     spark://<ip1>:<port1>,<ip2>:<port2>
yarn模式的写法
   master=yarn
注意:
  standalone式和yarn模式要通常配合deploy-mode来进行使用
  deploy-mode意为作业运行的方式,有两个选项:
    client  :默认值,driver或者sparkContext的创建与运行实在作业提交的机器上面完成
    cluster :driver的创建和运行,与executor的创建和运行都是在集群中来完成,也就是都在worker上面来完成创建初始化并运行
  通常,生产的deploy-mode用cluster,测试和开发用client。
object ScalaWordCount {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName(ScalaWordCount.getClass.getSimpleName)
    val sparkContext = new SparkContext(conf)
    val rdd:RDD[String] = sparkContext.textFile("C:\\Users\\70201\\Desktop\\wordcount.txt")
    rdd.flatMap(_.split("\\s+")).map((_,1)).reduceByKey(_+_).foreach({case(word,count)=>println(word+"---"+count)})
    sparkContext.stop()
  }
}

3. spark日志的管理

全局管理

就是项目classpath下面引入log4j.properties配置文件进行管理

# 基本日志输出级别为INFO,输出目的地为console
log4j.rootCategory=INFO, console

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n

# 输出配置的是spark提供的webui的日志级别


log4j.logger.org.spark_project.jetty=INFO
log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle=ERROR
log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO
log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO
log4j.logger.org.apache.parquet=ERROR
log4j.logger.parquet=ERROR

局部管理

就是在当前类中进行日志的管理。

import org.apache.log4j.{Level, Logger}

Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.apache.hadoop").setLevel(Level.WARN)
Logger.getLogger("org.spark_project").setLevel(Level.WARN)

4.打包spark程序

打包程序在下面
如果不需要第三方依赖的打包的话,直接使用idea打包:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打包完成

5.提交到虚拟机本地

spark程序提交到集群,就应该是通过spark-submit脚本来完成的。

spark-submit-wc-local.sh脚本

#!/bin/sh

SPARK_HOME=/opt/module/spark-2.4.3

${SPARK_HOME}/bin/spark-submit \
--class com.offcn.bigdata.spark.RemoteScalaWordCountApp \
--master local \
--deploy-mode client \
/root/spark/wc.jar \
hdfs://hadoop003:9000/test/input/wordcount.txt

打包程序

package com.offcn.bigdata.spark

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * @author ljh
 * @create 2020-12-06 18:17
 */
object RemoteScalaWordCountApp {
  def main(args: Array[String]): Unit = {
    if(args == null || args.length != 1) {
      println(
        """
          |Usage: <input>
          |""".stripMargin)
      System.exit(-1)
    }

    val Array(input) = args

    val conf = new SparkConf()
      .setAppName(s"${RemoteScalaWordCountApp.getClass.getSimpleName}")
    val sc = new SparkContext(conf)
    val lines: RDD[String] = sc.textFile(input)//加载hdfs的文件

    println("lines rdd's partition is: " + lines.getNumPartitions)
    //calc word's count
    val words:RDD[String] = lines.flatMap(line => line.split("\\s+"))
    val pairs:RDD[(String, Int)] = words.map(word => (word, 1))
    val ret:RDD[(String, Int)] = pairs.reduceByKey(myReduceFunc)

    //export data to external system
            ret.foreach{case (word, count) => {
                println(word + "--->" + count)
            }}
    //ret.saveAsTextFile(output)

    sc.stop()
  }
  def myReduceFunc(v1: Int, v2: Int): Int = {
    //        val i = 1 / 0 //为了验证lazy
    v1 + v2
  }
}

6.提交到spark集群

spark-submit-wc-standalone-client.sh

#!/bin/sh

SPARK_HOME=/opt/module/spark-2.4.3

${SPARK_HOME}/bin/spark-submit \
--class com.offcn.bigdata.spark.RemoteScalaWordCountApp \
--master spark://hadoop003:7077 \
--deploy-mode client \
--executor-cores 1 \
--total-executor-cores 2 \
--driver-memory 600M \
--executor-memory 600M \
/root/spark/wc.jar \
hdfs://hadoop003:9000/test/input/wordcount.txt

spark-submit-wc-standalone-cluster.sh

将driver提交到集群运行,driver会读取不到本地的wc.jar,所以要把wc.jar提交到hdfs

#!/bin/sh

SPARK_HOME=/opt/module/spark-2.4.3

${SPARK_HOME}/bin/spark-submit \
--class com.offcn.bigdata.spark.RemoteScalaWordCountApp \
--master spark://hadoop003:7077 \
--deploy-mode cluster \
--driver-cores 1 \
--executor-cores 1 \
--total-executor-cores 2 \
--driver-memory 600M \
--executor-memory 600M \
hdfs://hadoop003:9000/spark/wc.jar \
hdfs://hadoop003:9000/test/input/wordcount.txt

7.疑惑

一个疑惑的问题,在local的方式中,可以看到foreach的结果,但是client模式下面就看不到这个结果,这是为何?
在这里插入图片描述
算子操作都是在worker中执行的,包括foreach操作,所以要想看结果就应该去worker上面查看,而不是提交作业的本机。

8.提交到yarn集群

spark基于yarn集群的运行方式,是在国内最常见的一种方式。

package com.offcn.bigdata.spark

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
 * @author ljh
 * @create 2020-12-06 18:17
 */
object RemoteScalaWordCountApp {
  def main(args: Array[String]): Unit = {
    if(args == null || args.length != 2) {
      println(
        """
          |Usage: <input><output>
          |""".stripMargin)
      System.exit(-1)
}

val Array(input,output) = args

    val conf = new SparkConf()
      .setAppName(s"${RemoteScalaWordCountApp.getClass.getSimpleName}")
    val sc = new SparkContext(conf)
    val lines: RDD[String] = sc.textFile(input)//加载hdfs的文件

    println("lines rdd's partition is: " + lines.getNumPartitions)
    //calc word's count
    val words:RDD[String] = lines.flatMap(line => line.split("\\s+"))
    val pairs:RDD[(String, Int)] = words.map(word => (word, 1))
    val ret:RDD[(String, Int)] = pairs.reduceByKey(myReduceFunc)

    //export data to external system
            ret.foreach{case (word, count) => {
                println(word + "--->" + count)
            }}
    ret.saveAsTextFile(output)

sc.stop()
  }
def myReduceFunc(v1: Int, v2: Int): Int = {
      //        val i = 1 / 0 //为了验证lazy
  v1 + v2
    }
}

spark-submit-wc-yarn-client.sh

两个参数,指定输入和输出的位置

 #!/bin/sh
    
        SPARK_HOME=/opt/module/spark-2.4.3
        
        ${SPARK_HOME}/bin/spark-submit \
        --class com.offcn.bigdata.spark.RemoteScalaWordCountApp \
        --master yarn \
        --deploy-mode client \
        --executor-cores 1 \
        --num-executors 1 \
        --driver-memory 600M \
        --executor-memory 600M \
        /root/spark/wc1.jar \
        hdfs://hadoop003:9000/test/input/wordcount.txt \
        hdfs://hadoop003:9000/spark/wc

spark-submit-wc-yarn-cluster.sh

 #!/bin/sh
    
    SPARK_HOME=/opt/module/spark-2.4.3
    
    ${SPARK_HOME}/bin/spark-submit \
    --class com.offcn.bigdata.spark.RemoteScalaWordCountApp \
    --master yarn \
    --deploy-mode cluster \
    --driver-cores 1 \
    --executor-cores 1 \
    --num-executors 1 \
    --driver-memory 600M \
    --executor-memory 600M \
    hdfs://hadoop003:9000/spark/wc1.jar \
    hdfs://hadoop003:9000/test/input/wordcount.txt \
    hdfs://hadoop003:9000/spark/wc1

9.报错

大家直接基于yarn模式进行运行,肯定会报错,一般报的错误就是虚拟内存超过的物理内存这个错误。
Container killed by YARN for exceeding memory limits. 15.6 GB of 15.5 GB physical memory used.
解决问题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值