SparkCore课堂讲义
第一讲 Spark基础核心知识
课程大纲 | 课程内容 | 学习效果 | 掌握目标 |
Spark简介 | 大数据生态发展 | 了解 | |
什么是Spvark | |||
Spark开发环境 | Spark standalone | 掌握 | |
Spark HA | 掌握 | ||
Spark核心概念 | Spark核心概念 | 掌握 | |
Spark编程体验 | Spark项目创建 | 掌握 | |
Spark项目编码 | 掌握 |
一、什么是Spark
(一)大数据生态
(二)什么是Spark
1、Spark特点
快的原因:
1. 基于内存计算
2. 计算和数据的分离
3. 基于DAGScheduler的计算划分
4. 只有一次的Shuffle输出操作
Ease of Use:
Spark提供超过80多个高阶算子函数,来支持对数据集的各种各样的计算,使用的时候,可以使用java、scala、python、R,非常灵活易用。
df = spark.read.json("logs.json")
df.where("age > 21")
.select("name.first")
.show()
Generality:
通用性如下图1-3所示:
Runs Everywhere:
Spark程序可以再多个平台上面运行,如下图1-4所示:
2、Spark概述总结
什么是Spark呢?它就是一个集成离线计算,实时计算,SQL查询,机器学习,图计算为一体的通用的计算框架。
何为通用?就是在一个项目中,既可以使用离线计算,也可以使用其他比如,SQL查询,机器学习,图计算等等,而这是Spark最最最强大的优势,没有之一。
而这一切的基础是SparkCore,速度比传统的mr快的原因就是基于内存的计算。
Spark开发过程中,使用到的模型——RDD(Resilient Distributed Dataset, 弹性式分布式数据集),在编程中起到了非常重要的作用。
3、RDD概述
何为RDD?其实RDD就是一个不可变的scala的并行集合。
Spark的核心概念就是RDD,指的是一个不可变、可分区、里面元素可并行计算的集合,这个数据的全部或者部分可以缓存在内存中,在多次计算间被重用。
RDD在抽象来说是一种元素集合,包含了数据。他是被分区的,分为多个分区,每个分区分布在集群中的不同worker节点上面,从而让RDD中的数据可以被并行操作。
RDD通常通过Hadoop上的文件,即HDFS文件或者Hive表来进行创建;也可以通过RDD的本地创建转换而来。
传统的MapReduce虽然具有自动容错、平衡负载和可拓展性的优点,但是其最大缺点是采用非循环式的数据流模型,使得在迭代计算式要进行大量的磁盘IO操作。RDD正式解决这个缺点的抽象方法。
RDD最重要的特性就是,提供了容错性,可以自动从节点失败中恢复过来。即如果某个节点上的RDD Partition,因为节点故障,导致数据丢失,那么RDD会自动通过自己的数据来源重新计算该Partition。这一切对使用者是透明的,这一切的背后工作都是通过RDD的lineage特性来实现的。
RDD的数据默认情况下是存放在内存中的,但是内存资源不足的时候,Spark会自动将RDD数据溢出到磁盘(弹性)。
4、RDD特性
通过上述的描述,我们可以从以下几个方面来描述RDD
(一)弹性
如果内存充足,那集合数据的存储和计算,就都在内存中完成;如果内存不足,需要有一部分数据溢出到磁盘,然后在磁盘完成存储和计算。
(二)分布式
就和之前学习的分布式概念一样,一个集合的数据被拆分成多个部分,这每一个部分被称之为一个分区partition,还是一个scala的不可变的集合。默认情况下,partition是和hdfs中data-block块对应的,spark加载hdfs文件时,一个data-block块对应一个partition。
所以,对RDD的操作,本质上是对着每一个RDD对应分区partition的操作。
(三)数据集
存放数据的集合
而Spark就是对这个RDD及其集合功能算子的实现。
RDD,弹性式分布式数据集,是Spark的第一代编程模型。
说白了RDD就是一个抽象数据类型。
(四)RDD之间是存在依赖关系的
这些RDD之间的依赖关系,就形成了一个RDD的有向无环图DAG,依赖关系称之为RDD血缘关系或者血统,因为lineage。
依赖关系呢,分为了两种:窄依赖和宽依赖。具体我们会在spark stage阶段划分的时候进行具体说明。
(五)移动计算优于移动数据
partition提供的最佳计算位置,利于数据处理的本地化即计算向数据移动而不是移动数据。
总结如下图1-5所示:
- 一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。
- 一个计算每个分区的函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。
- RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。
- 一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。
- 一个列表,存储存取每个Partition的对应数据的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
5、RDD在Spark中的地位和作用
(一)为什么会有Spark
因为传统的并行计算模型无法有效的进行交互式计算;而Spark的使命便是解决这个问题,这也是它存在的价值和理由。
(二)Spark如何解决迭代计算
其主要实现思想就是RDD,把所有计算的数据保存在分布式的内存中。迭代计算通常情况下都是对同一个数据集做反复的迭代计算,数据在内存中将大大降低IO操作。这也是Spark设计的核心:内存计算。
(三)Spark如何实现交互式计算
因为Spark是用scala语言实现的,Spark和scala能够紧密的集成。所以Spark可以完美的运用scala的解释器,使得其中的scala可以向操作本地集合对象一样轻松的操作分布式数据集。
(四)Spark和RDD的关系
可以理解为:RDD是一种具有容错性,基于内存的集群计算抽象方法,Spark则是这个抽象方法的实现。
二、Spark分布式环境安装
当前大纲中使用的Spark的版本是2.4.7,最新的版本应该3.0.1。
下载地址:https://archive.apache.org/dist/spark/spark-2.4.7/
提供的安装包:
spark-2.4.7.tgz ---->源码包
spark-2.4.7-bin-hadoop2.7.tgz ---->安装包
(一)基于Windows的环境体验
1、解压
2、启动%SPARK_HOME%\bin\spark-shell.cmd脚本
启动界面如下图1-7所示、
3、执行入门案例
(1)spark-shell终端代码:
scala> sc.textFile("E:/data/hello.txt")
.flatMap(_.split("\\s+"))
.map((_, 1))
.reduceByKey(_+_)
.foreach(println)
(2)结果查看
(3)Web-UI
能够得出的基本结论是什么?
- Spark的application,可以有非常多的job作业,和mr不同,一个应用就提交一个job就行。
- job的执行,需要action算子操作触发,否则不会执行,触发的操作就是spark作业执行的动因。
- spark job作业的执行是分stage阶段的
spark job作业的执行stage阶段形成了一个stage的DAG有向无环图
(二)Spark分布式环境安装
1、解压
[root@node01 ~]$ tar -zxvf spark-2.4.7-bin-hadoop2.7.tgz -C /export/servers/
2、重命名
[root@node01 ~]$ mv spark-2.4.7-bin-hadoop2.7/ spark
3、添加环境变量
vim /etc/profile
export SPARK_HOME=/export/servers/spark
export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin
4、环境变量生效
[root@node01 ~]$ source /etc/profile
5、修改配置文件
(1)$SPARK_HOME/conf/slaves
a)、拷贝slaves和spark-env.conf文件
[root@node01 conf]# mv slaves.template slaves
[root@node01 conf]# mv spark-env.sh.template spark-env.sh
b)、修改slaves文件内容
node02
node03
(2)$SPARK_HOME/conf/spark-env.sh
a)添加如下内容:
export JAVA_HOME=/export/servers/jdk1.8.0_141
export SPARK_MASTER_HOST=node01
export SPARK_MASTER_PORT=7077
b)发送spark到其它节点中
scp -r spark/ node02:$PWD
scp -r spark/ node03:$PWD
6、启动并体验
(1)启动
使用$SPARK_HOME/sbin目录下的脚本start-all.sh
(2)停止
使用$SPARK_HOME/sbin目录下的脚本stop-all.sh
stop-all.sh
(3)验证
启动起来之后,spark的主节点master会类似resourcemanager提供一个web的ui,访问地址为:http://master-ip:8080
sbin/start-all.sh
sbin/stop-all.sh
(4)提交任务&执行程序
[root@node01 spark]# bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077 \
--driver-memory 1g \
--executor-memory 1g \
--executor-cores 2 \
--queue default \
./examples/jars/spark-examples_2.11-2.4.7.jar \
100
(三)Spark分布式HA环境安装
因为在目前情况下,集群中只有一个Master,如果master挂掉,便无法对外提供新的服务,显然有单点故障问题,解决方法就是master的ha。
有两种方式解决单点故障,一种基于文件系统FileSystem(生产中不用),还有一种基于Zookeeper(使用)。
配置基于Zookeeper的一个ha是非常简单的,只需要在spark-env.sh中添加一句话即可。
注释掉如下内容:
#SPARK_MASTER_HOST=node01
export SPARK_MASTER_PORT=7077
添加上如下内容:配置的时候保证下面语句在一行,否则配置不成功,每个-D参数使用空格分开
export SPARK_DAEMON_JAVA_OPTS="
-Dspark.deploy.recoveryMode=ZOOKEEPER
-Dspark.deploy.zookeeper.url=node01:2181,node02:2181,node03:2181
-Dspark.deploy.zookeeper.dir=/spark"
- spark.deploy.recoveryMode设置成 ZOOKEEPER
- spark.deploy.zookeeper.urlZooKeeper URL
- spark.deploy.zookeeper.dir ZooKeeper 保存恢复状态的目录,缺省为 /spark
因为ha不确定master在node01上面启动,所以将
export SPARK_MASTER_HOST=node01注释掉
[root@node01 conf]# scp -r spark-env.sh node02:$PWD [root@node01 conf]# scp -r spark-env.sh node03:$PWD |
最后别忘了,同步spark-env.sh到其它机器。
同步完毕之后,重启spark集群!
node01的master状态
node02也启动master
start-master.sh,其状态为:
(1)提交任务&执行程序
[root@node01 spark]# bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node01:7077,node02:7077 \
--driver-memory 1g \
--executor-memory 1g \
--executor-cores 2 \
--queue default \
./examples/jars/spark-examples_2.11-2.4.7.jar \
100
ha验证,要干掉alive的master,观察standby的master
node02的状态缓慢的有standby转变为alive
(四)动态增删worker节点
1、上线
不需要在现有集群的配置上做任何修改,只需要准备一台worker机器即可,可和之前的worker的配置相同。
spark]# sbin/start-slave.sh node01:7077 -c 4 -m 1024M
2、下线
(五)Spark分布式Yarn环境安装
1)修改hadoop配置文件yarn-site.xml,添加如下内容:
[root@node01 hadoop]$ vi yarn-site.xml
<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认是true -->
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<!--是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认是true -->
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
2)修改spark-env.sh,添加如下配置:
[root@node01 conf]# vi spark-env.sh
YARN_CONF_DIR=/export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop
HADOOP_CONF_DIR=/export/servers/hadoop-2.6.0-cdh5.14.0/etc/hadoop
3)client模式
[root@node01 spark]# bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode client \
./examples/jars/spark-examples_2.11-2.4.7.jar \
100
注意:在提交任务之前需启动HDFS以及YARN集群。
4)cluster模式
[root@node01 spark]# bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
./examples/jars/spark-examples_2.11-2.4.7.jar \
100
三、Spark核心概念
(一)、名词解释
- ClusterManager:在Standalone(上述安装的模式,也就是依托于spark集群本身)模式中即为Master(主节点),控制整个集群,监控Worker。在YARN模式中为资源管理器ResourceManager(国内spark主要基于yarn集群运行,欧美主要基于mesos来运行)。
- Application:Spark的应用程序,包含一个Driver program和若干Executor。
- SparkContext:Spark应用程序的入口,负责调度各个运算资源,协调各个Worker Node上的Executor。
- Worker:从节点,负责控制计算节点,启动Executor。在YARN模式中为NodeManager,负责计算节点的控制,启动的进程叫Container。
- Driver:运行Application的main()函数并创建SparkContext(是spark中最重要的一个概念,是spark编程的入口,作用相当于mr中的Job)。
- Executor:执行器,在worker node上执行任务的组件、用于启动线程池运行任务。每个Application拥有独立的一组Executors。
- SparkContext:整个应用的上下文,控制应用的生命周期,是spark编程的入口。
- RDD:Spark的基本计算单元,一组RDD可形成执行的有向无环图RDD Graph。
RDD是弹性式分布式数据集,理解从3个方面去说:弹性、数据集、分布式。
是Spark的第一代的编程模型。
- DAGScheduler:实现将Spark作业分解成一到多个Stage,每个Stage根据RDD的Partition个数决定Task的个数,然后生成相应的Task set放到TaskScheduler中。DAGScheduler就是Spark的大脑,中枢神经。
- TaskScheduler:将任务(Task)分发给Executor执行。
- Stage:一个Spark作业一般包含一到多个Stage。
- Task:一个Stage包含一到多个Task,通过多个Task实现并行运行的功能。task的个数由rdd的partition分区决定,spark是一个分布式计算程序,所以一个大的计算任务,就会被拆分成多个小的部分,同时进行计算。一个partition对应一个task任务。
- Transformations:转换(Transformations) (如:map, filter, groupBy, join等),Transformations操作是Lazy的,也就是说从一个RDD转换生成另一个RDD的操作不是马上执行,Spark在遇到Transformations操作时只会记录需要这样的操作,并不会去执行,需要等到有Actions操作的时候才会真正启动计算过程进行计算。
- Actions:操作/行动(Actions)算子 (如:count, collect, foreach等),Actions操作会返回结果或把RDD数据写到存储系统中。Actions是触发Spark启动计算的动因。
- SparkConf:负责存储配置信息。作用相当于hadoop中的Configuration。
(二)、Spark官网组件说明
官网组件说明如下图1-19所示:
Spark应用程序作为集群上的独立进程集运行,由主程序(称为驱动程序)中的SparkContext对象协调。
具体来说,要在集群上运行,SparkContext可以连接到几种类型的集群管理器(Spark自己的独立集群管理器、Mesos或YARN),这些管理器可以跨应用程序分配资源。一旦连接,Spark将获取集群中节点上的执行器,这些执行器是为应用程序运行计算和存储数据的进程。接下来,它将应用程序代码(由传递给SparkContext的JAR或Python文件定义)发送给执行器。最后,SparkContext将任务发送给执行器以运行。
四、Spark编程体验
(一)、Spark项目的创建
1、项目依赖管理
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<scala.version>2.11.8</scala.version>
<scala.compat.version>2.11</scala.compat.version>
<hadoop.version>2.7.4</hadoop.version>
<spark.version>2.2.0</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.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive-thriftserver_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- <dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
<version>${spark.version}</version>
</dependency>-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql-kafka-0-10_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<!--<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.6.0-mr1-cdh5.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.14.0</version>
</dependency>-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<!-- 指定编译java的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
<!-- 指定编译scala的插件 -->
<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-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<useFile>false</useFile>
<disableXmlReport>true</disableXmlReport>
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
</includes>
</configuration>
</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>chapter1.HelloScala</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
(二)、项目编码
1、spark入门程序wordcount
package com.offcn.bigdata.spark.p1
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* scala版本的wordcount
*/
object ScalaWordCountApp {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName(s"${ScalaWordCountApp.getClass.getSimpleName}")
.setMaster("local[*]")
val sc = new SparkContext(conf)
//加载数据
val file: RDD[String] = sc.textFile("file:/E:/data/spark/hello.txt")
//按照分隔符进行切分
val words:RDD[String] = lines.flatMap(line => line.split("\\s+"))
//每个单词记为1次
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(println)
}
sc.stop()
}
def myReduceFunc(v1: Int, v2: Int): Int = {
v1 + v2
}
}
2、Master URL说明
首先在编程过程中,至少需要给spark程序传递一个参数master-url,通过sparkConf.setMaster来完成。改参数,代表的是spark作业的执行方式,或者指定的spark程序的cluster-manager的类型。
master | 含义 | |
local | 程序在本地运行,同时为本地程序提供一个线程来处理 | |
local[M] |
| |
local[*] | 程序在本地运行,同时为本地程序分配机器可用的CPU core的个数工作线程来处理 | |
local[M, N] | 程序在本地运行,同时为本地程序分配M个工作线程来处理,如果提交程序失败,会进行最多N次的重试 | |
spark://ip:port |
| |
spark://ip1:port1,ip2:port2 | 基于standalone的ha模式运行,提交撑到ip对应的master上运行 | |
yarn/启动脚本中的deploy-mode配置为cluster | 基于yarn模式的cluster方式运行,SparkContext的创建在NodeManager上面,在yarn集群中 | |
yarn/启动脚本中的deploy-mode配置为client | 基于yarn模式的client方式运行,SparkContext的创建在提交程序的那台机器上面,不在yarn集群中 |
3.Spark日志管理
(1)全局管理
就是项目classpath下面引入log4j.properties配置文件进行管理,由于我们这里已经配置过了项目的依赖管理,所以只需要将log4j.properties放置到spark-common模块的resources目录下即可。
# 基本日志输出级别为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
(2)局部管理
就是在当前类中进行日志的管理。
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)
(三)、spark程序的其他提交方式
1、加hdfs中的文件
object RemoteSparkWordCountOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setMaster("local[*]")
.setAppName("SparkWordCount")
val sc = new SparkContext(conf)
//load data from file
val linesRDD:RDD[String] = sc.textFile("hdfs://ns1/data/spark/hello.txt")
val ret = linesRDD.flatMap(_.split("\\s+")).map((_, 1)).reduceByKey(_ + _)
ret.foreach{case (word, count) => println(word + "---" + count)}
sc.stop()
}
程序出现如下问题:
java.lang.IllegalArgumentException: java.net.UnknownHostException: ns1
解决方案,最简单的就是将hadoop的两个配置文件core-site.xml和hdfs-site.xml添加到项目的classpath中即可。
但是此时在此基础之上,将textFile去加载本地的文件
sc.textFile("E:/data/hello.txt")
则会报错:
java.lang.IllegalArgumentException: Pathname /E:/data/hello.txt from hdfs://ns1/E:/data/hello.txt is not a valid DFS filename
原因就在于,已经在classpath下面加载了hdfs-site.xml和core-site.xml的配置文件,则会自动理解输入的文件路径为hdfs的,自然会报错。所以,在此情况下还想加载本地文件,那么就告诉机器以本地文件的格式或者协议读取即可。
val linesRDD:RDD[String] = sc.textFile("file:/E:/data/hello.txt")
2.提交spark程序到集群中
首先需要将spark-core模块进行打包,其次上传到集群中,才可以进行提交作业到spark或者yarn集群中运行。
(1)Standalone集群
Client
bin/spark-submit \
--class chapter1.WordCount \
--master spark://node01:7077 \
/root/WordCount.jar \
hdfs://node01:8020/wordcount/input/words.txt
Cluster
bin/spark-submit \
--class chapter1.WordCount \
--master spark://node01:7077 \
/root/WordCount.jar \
hdfs://node01:8020/wordcount/input/words.txt \
hdfs://node01:8020/wordcount/input/output1