Spark学习(二)--任务提交

这次我们主要介绍spark的任务提交的方式和代码的编写

  • spark的常用角色介绍
  • spark-shell
  • 代码任务提交

1. spark常用的角色介绍

Spark 是基于内存计算的大数据并行计算框架。 因为其基于内存计算, 比Hadoop 中 MapReduce 计算框架具有更高的实时性, 同时保证了高效容错性和可伸缩性。 从 2009 年诞生于 AMPLab 到现在已经成为 Apache 顶级开源项目, 并成功应用于商业集群中, 学习 Spark 就需要了解其架构。
Spark 架构图如下:
在这里插入图片描述
Spark 架构使用了分布式计算中master-slave模型,master是集群中含有master进程的节点,slave 是集群中含有worker进程的节点。

  • Driver-Program:运行main函数并且新建SparkContext的程序。
  • Application:基于Spark的应用程序,包含了driver程序和集群上的executor。
  • Cluster Manager:指的是在集群上获取资源的外部服务。目前有三种类型
    • Standalone:spark原生的资源管理,由Master负责资源的分配
    • Apache Mesos:与hadoop、MR兼容性良好的一种资源调度框架
    • Hadoop Yarn:主要是指Yarn中的ResourceManager
  • Worker Node:集群中任何可以运行Application代码的节点,在Standalone模式中指的是通过 slaves 文件配置的 Worker 节点, 在 Spark on Yarn 模式下就是 NodeManager 节点
  • Executor:是在一个worker-node上为某应⽤启动的⼀个进程,该进程负责运行任务, 并且负责将数据存在内存或者磁盘上。 每个应⽤都有各自独立的 executor。
  • Task:被送到某个executor上的工作单元。

2. spark-shell

spark-shell 是 Spark 自带的交互式 Shell 程序, 方便用户进行交互式编程, 用户可以在该命令行下用 scala 编写 spark 程序。

2.1 读取本地文件

单机模式: 通过本地 N 个线程跑任务, 只运行一个 SparkSubmit 进程。

  • 需求
    读取本地文件a.txt, 实现文件内的单词计数。 本地文件 words.txt 内容如下:
hello me
hello you
hello her
  • 实现
//1.启动shell命令
$sprak/bin/spark-shell --master local[2]
//2. 输入读取命令
sc.textFile("file:///root///temp///a.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect

//代码说明
1. sc: Spark-Shell 中已经默认将 SparkContext 类初始化为对象 sc。 用户代码如
果需要用到, 则直接应用 sc 即可。
2. textFile:读取数据文件
3. flatMap:对文件中的每一行数据进行压平切分,这里按照空格分隔。
4. map:对出现的每一个单词记为 1(word, 1)
5. reduceByKey:对相同的单词出现的次数进行累加
6. collect:触发任务执行, 收集结果数据。
  • 运行结果
    在这里插入图片描述

2.2 读取HDFS的文件

需求不变,这里需要修改配置文件

//1. spark与hadoop整合,修改配置文件 spark-env.sh
#添加 HADOOP_CONF_DIR 指定hadoop集群中配置文件的路径
export HADOOP_CONF_DIR=/export/server/hadoop-2.7.4/etc/hadoop

//2. 启动HDFS,重启spark

//3. 上传a.txt到HDFS目录
hadoop fs -put a.txt /

//4. 输入下面的命令进行计算
sc.textFile("/a.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect

2.3 运行 spark-shell 指定具体的 master 地址

  • 需求
    spark-shell 运行时指定具体的 master 地址, 读取 HDFS 上的数据, 做单词计数, 然后将结果保存在 HDFS 上。
  • 启动的执行命令
spark-shell \
--master spark://nodel01:7077 \
--executor-memory 1g \
--total-executor-cores 2

参数说明:
 --master spark://hdp-node-01:7077   指定 Master 的地址
--executor-memory 1g 指定每个 worker 可用内存为 1g
--total-executor-cores 2  指定整个集群使用的 cup 核数为 2 个

注意:
如果启动 spark shell 时没有指定 master 地址, 但是也可以正常启动 spark shell和执行 spark shell 中的程序, 其实是启动了 spark 的 local 模式, 该模式仅在本机启动一个进程, 没有与集群建立联系。

  • 执行运算的命令
sc.textFile("/a.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).saveAsTextFile("/wc")
  • 在HDFS的查看运行的结果

3 .代码示例

spark-shell 仅在测试和验证我们的程序时使用的较多, 在生产环境中, 通常会在 IDEA 中编写程序, 然后打成 jar 包, 最后提交到集群。 最常用的是创建一个Maven 项目, 利用 Maven 来管理 jar 包的依赖。

3.1 Scala代码

  • pom依赖
 <properties>  
        <scala.version>2.11.8</scala.version>
        <hadoop.version>2.7.4</hadoop.version>
        <spark.version>2.0.2</spark.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <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>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass></mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  • Scala代码
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD


//todo:需求:利用scala语言实现spark wordcount程序
object WordCount_Online {
  def main(args: Array[String]): Unit = {
      //1、创建sparkConf对象,设置appName和master的地址
      val sparkConf: SparkConf = new SparkConf().setAppName("WordCount_Online")

       //2、创建sparkcontext对象
        val sc = new SparkContext(sparkConf)

      //设置日志输出级别
        sc.setLogLevel("WARN")

       // 3、读取数据文件
        val data: RDD[String] = sc.textFile(args(0))

       //4、切分文件中的每一行,返回文件所有单词
       val words: RDD[String] = data.flatMap(_.split(" "))

      //5、每个单词记为1,(单词,1)
      val wordAndOne: RDD[(String, Int)] = words.map((_,1))

      //6、相同单词出现的次数累加
      val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)

      //按照单词出现的次数降序排列
      val sortResult: RDD[(String, Int)] = result.sortBy(_._2,false)

      //7、结果数据保存在HDFS上
      sortResult.saveAsTextFile(args(1))


    //8、关闭sc
    sc.stop()
  }
}

  • 打包完成后,直接提交代码到集群上运行,命令如下
 spark-submit --class com.wordcount.WordCount_Online
  --master spark://node1:7077
  --executor-memory 1G
  --total-executor-cores 2
    /root/original-spark-2.0.jar 
    /words.txt /out100

Java代码

  • 在相同的项目,使用相同的pom
  • 代码如下
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

//todo:需求:利用java语言开发spark wordcount程序
public class WordCount_Java {
    public static void main(String[] args) {
        //1、创建sparkConf对象
        SparkConf sparkConf = new SparkConf().setAppName("WordCount_Java").setMaster("local[2]");
        //2、创建sparkContext对象
        JavaSparkContext jsc = new JavaSparkContext(sparkConf);
        //3、读取数据文件
        JavaRDD<String> dataJavaRDD = jsc.textFile("d:\\words.txt");
        //4、切分每一行
        JavaRDD<String> wordsJavaRDD = dataJavaRDD.flatMap(new FlatMapFunction<String, String>() {
            public Iterator<String> call(String line) throws Exception {
                String[] words = line.split(" ");
                return Arrays.asList(words).iterator();
            }
        });
        //5、每个单词记为1
        JavaPairRDD<String, Integer> wordAndOneJavaPairRDD = wordsJavaRDD.mapToPair(new PairFunction<String, String, Integer>() {
            public Tuple2<String, Integer> call(String word) throws Exception {
                return new Tuple2<String, Integer>(word, 1);
            }
        });
        //6、相同单词出现的次数累加
        JavaPairRDD<String, Integer> resultJavaPairRDD = wordAndOneJavaPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
            public Integer call(Integer v1, Integer v2) throws Exception {
                return v1 + v2;
            }
        });

        //按照单词出现的次数进行降序排列,思想:先把(单词,次数)位置颠倒(次数,单词)
        JavaPairRDD<Integer, String> reverseJavaPairRDD = resultJavaPairRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
            public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple2) throws Exception {
                return new Tuple2<Integer, String>(tuple2._2, tuple2._1);
            }
        });
        // 按照单词出现的次数进行降序排列 调用sortByKey方法,然后将(次数,单词)颠倒为(单词,次数)
        JavaPairRDD<String, Integer> sortJavaPairRDD = reverseJavaPairRDD.sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
            public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple2) throws Exception {
                return new Tuple2<String, Integer>(tuple2._2, tuple2._1);
            }
        });

        //7、收集结果数据
        List<Tuple2<String, Integer>> finalResult = sortJavaPairRDD.collect();


        //8、循环打印结果数据
        for(Tuple2<String, Integer> tuple:finalResult){
            System.out.println(tuple._1+"出现的次数"+tuple._2);
        }

        //9、关闭sparkcontext
        jsc.stop();

    }
}

  • 打包提交任务的命令相同

本次介绍结束

猜你喜欢

转载自blog.csdn.net/weixin_42229056/article/details/83153937