spark基于不同模式下搭建集群及spark资源请求任务调度,广播变量和累加器

spark环境搭建

standalone模式搭建

1、上传解压,配置环境变量 配置bin目录 2、修改配置文件 conf mv spark-env.sh.template spark-env.sh添加以下代码

export SPARK_MASTER_IP=master
export SPARK_MASTER_PORT=7077

export SPARK_WORKER_CORES=2
export SPARK_WORKER_INSTANCES=1
export SPARK_WORKER_MEMORY=2g
export JAVA_HOME=/usr/local/soft/jdk1.8.0_171

master相当于RM worker相当于NM,增加从节点配置

mv slaves.template slaves
node1
node2

3、复制到其它节点

scp -r spark-2.4.5 node1:`pwd`
scp -r spark-2.4.5 node2:`pwd`

4、在主节点执行启动命令 启动集群,在master中执行

./sbin/start-all.sh
http://master:8080/  访问spark ui
  1. standalone client模式 日志在本地输出,一班用于上线前测试(bin/下执行)

需要进入到spark-examples_2.11-2.4.5.jar 包所在的目录下执行

cd /usr/local/soft/spark-2.4.5/examples/jars
spark-submit --class org.apache.spark.examples.SparkPi --master spark://master:7077 --executor-memory 512m --total-executor-cores 1 spark-examples_2.11-2.4.5.jar 100
  1. standalone cluster模式 上线使用,不会再本地打印日志

    spark-submit --class org.apache.spark.examples.SparkPi --master spark://master:7077 --driver-memory 512m --deploy-mode cluster --supervise --executor-memory 512M --total-executor-cores 1 spark-examples_2.11-2.4.5.jar 100

spark-shell spark 提供的一个交互式的命令行,可以直接写代码

spark-shell --master spark://master:7077

运行自己写的代码 1、注释掉setMaster 2、将项目打包 3、上擦到服务器 4、提交任务 spark-submit --class com.shujia.spark.core.Demo18PI --master spark://master:7077 --executor-memory 512m --total-executor-cores 1 spark-1.0.jar

package sparkcore

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

import scala.util.Random

object Demo18PI {

def main(args: Array[String]): Unit = {

  val conf: SparkConf = new SparkConf().setAppName("PI").setMaster("local")

  val sc = new SparkContext(conf)

  val list: Range = 0 until 10000000

  //构建一个很大的RDD
  val listRDD: RDD[Int] = sc.parallelize(list)

  //模拟生成点
  val pointRDD: RDD[(Double, Double)] = listRDD.map(i => {
    //模拟点
    val x: Double = Random.nextDouble() * 2 - 1
    val y: Double = Random.nextDouble() * 2 - 1
    (x, y)

  })
  //取出园内的点
  val yuanPointRDD: RDD[(Double, Double)] = pointRDD.filter {
    case (x: Double, y: Double) =>
      //计算点到圆心的距离
      x * x + y * y <= 1
  }

  //计算PI值
  val PI: Double = yuanPointRDD.count().toDouble / list.length * 4.0

  println("PI:"+PI)
}

}

整合yarn搭建Spark集群

在公司一般不适用standalone模式,因为公司一般已经有yarn 不需要搞两个资源管理框架停止spark集群 在spark sbin目录下执行 ./stop-all.sh

spark整合yarn只需要在一个节点整合, 可以删除node1 和node2中所有的spark 文件

1、增加hadoop 配置文件地址

vim spark-env.sh
增加
export HADOOP_CONF_DIR=/usr/local/soft/hadoop-2.7.6/etc/hadoop

2、往yarn提交任务需要增加两个配置 yarn-site.xml(/usr/local/soft/hadoop-2.7.6/etc/hadoop/yarn-site.xml)

先关闭yarn stop-yarn.sh

<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>

<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>

4、同步到其他节点,重启yarn

scp -r yarn-site.xml node1:`pwd`
scp -r yarn-site.xml node2:`pwd`

启动yarn start-yarn.sh

cd /usr/local/soft/spark-2.4.5/examples/jars

3.spark on yarn client模式 日志在本地输出,一班用于上线前测试

spark-submit --class org.apache.spark.examples.SparkPi --master yarn-client --executor-memory 512M --num-executors 2 spark-examples_2.11-2.4.5.jar 100

4.spark on yarn cluster模式 上线使用,不会再本地打印日志 减少io

spark-submit --class org.apache.spark.examples.SparkPi --master yarn-cluster --executor-memory 512m --num-executors 2 --executor-cores 1 spark-examples_2.11-2.4.5.jar 100

获取yarn程序执行日志 执行成功之后才能获取到 yarn logs -applicationId application_1626695992877_0001

image.png

运行自己写的代码 1、注释掉setMaster, 修改输入输出路径 2、将项目打包 3、上擦到服务器 4、提交任务

spark-submit --class com.shujia.spark.core.Demo20Submit --master yarn-cluster --executor-memory 512m --total-executor-cores 1 spark-1.0.jar

杀死yarn 任务 yarn application -kill application_1626660789491_0012

hdfs webui http://node1:50070

yarn ui http://node1:8088

Spark资源申请和任务调度

image.png

Spark运行流程

image.png

1) 任务提交后,都会先启动 Driver 程序;

2) 随后 Driver 向集群管理器注册应用程序;

3) 之后集群管理器根据此任务的配置文件分配 Executor 并启动;

4) Driver 开始执行 main 函数,Spark 查询为懒执行,当执行到 Action 算子时开始反向推算,根据宽依赖进行 Stage 的划分,随后每一个 Stage 对应一个 Taskset,Taskset 中有多个 Task,查找可用资源 Executor 进行调度;

5) 根据本地化原则,Task 会被分发到指定的 Executor 去执行,在任务执行的过程中,Executor 也会不断与 Driver 进行通信,报告任务运行情况。

累加器

package sparkcore

import java.lang

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

object Demo21Accumulator {
def main(args: Array[String]): Unit = {
  val conf: SparkConf = new SparkConf().setMaster("local").setAppName("Accumulator")

  val sc = new SparkContext(conf)

  val rdd: RDD[Int] = sc.parallelize(List(1,2,3,4,5,6,7,8,9))

  /**
    * 累加器,只能累加
    *
    * 累加器只能在Driver中定义
    * 累加器只能在Executor累加
    * 了假期只能在Driver读取
    */
  //1、在Driver端定义累加器
  val accumulator: LongAccumulator = sc.longAccumulator

  rdd.foreach(i=>
  //2、在Executor端进行累加
    accumulator.add(i)


  )
  //3、在Driver带你去累加结果
  val count: lang.Long = accumulator.value

  println(count)

  /**
    * 累加器的使用
    * 如果不使用累加器需要单独启动一个job计算总人数
    * 使用了假期,乐嘉计算和班级人数的计算在一起计算出来
    */

  val students: RDD[String] = sc.textFile("data/students.txt")

  //定义累加器
  val studentsNum: LongAccumulator = sc.longAccumulator

  val KvRDD: RDD[(String, Int)] =students.map(stu=>{

    //累加
    studentsNum.add(1)

    val clazz: String = stu.split(",")(4)
    (clazz,1)
  })

  val clazzNumRDD: RDD[(String, Int)] = KvRDD.reduceByKey(_+_)
  //学生总人数
  val stuNum: lang.Long = studentsNum.value

  clazzNumRDD.foreach(println)
}

}

package sparkcore

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

object Demo22Broadcast {
 def main(args: Array[String]): Unit = {

   val conf: SparkConf = new SparkConf().setAppName("Broadcast").setMaster("local")

   val sc = new SparkContext(conf)

   val students: RDD[String] = sc.textFile("data/students.txt")

   //   val ids = List("1500100983","1500100911","1500100932","1500100915","1500100961")
   //
   //   val studentfilter: RDD[String] =students.filter(stu=>{
   //     val id: String = stu.split(",")(0)
   //     ids.contains(id)
   //   })
   //   studentfilter.foreach(println)

   /**
     * 广播变量
     */


   val ids = List("1500100983", "1500100911", "1500100932", "1500100915", "1500100961")

   //1、在Driver端将一个变量广播出去
   val broId: Broadcast[List[String]] = sc.broadcast(ids)


   val filterRDD: RDD[String] = students.filter(student => {
     val id: String = student.split(",")(0)

     //2、在Executor使用广播变量
     val value: List[String] = broId.value
     value.contains(id)
  })
   filterRDD.foreach(println)


   /**
     * 广播变量的应用
     *
     * 实现map join
     * 将小表加载到内存中,在map端进行关联
     */

   val students1: RDD[String] = sc.textFile("data/students.txt")
   val scores: RDD[String] = sc.textFile("data/score.txt")


   /**
     * collect:将RDD的数据拉取到RDriver端的内存中
     */

   val list: Array[String] = students1.collect()


   val studentMap: Map[String, String] = list.map(stu => {
     val id: String = stu.split(",")(0)
    (id, stu)
  }).toMap

   //将小表广播
   val broStudentMap: Broadcast[Map[String, String]] = sc.broadcast(studentMap)

   val stucoInfo: RDD[String] =scores.map(sco => {
     val id: String = sco.split(",")(0)

     //读取广播变量
     val value: Map[String, String] = broStudentMap.value

     //使用id到学生表的map中获取学生信息
     val studentInfo: String = value.getOrElse(id, "默认值")

     studentInfo + "\t" + sco
  })
   stucoInfo.foreach(println)

}

}

 

posted @ 2021-07-19 23:32  tonggang_bigdata  阅读(525)  评论(0编辑  收藏  举报