Spark-day01
1.学习目标
- 了解spark相关背景以及其框架特点
- 掌握搭建spark集群(尤其是高可用集群搭建) (重点)
- 掌握spark应用程序开发以及运行 (重点)
- 掌握Spark框架中的角色 (重点)
- Spark概述
- 官网:http://spark.apache.org/
- Apache Spark™ is a unified analytics engine for large-scale data processing.
- Spark是一个统一的分布式大数据处理分析引擎
- 统一:Spark能够处理离线数据、实时数据、图计算、机器学习以及AI。
- 大数据处理分析引擎:Spark只是对数据进行分析处理,并不包含数据存储的。HDFS 、Hbase、Hive、文件系统、Flume、Kafka、Mysql、Oracel、亚马逊云。
- 分布式:Spark一般是主从结构,以集群形式存在
- Spark是一个统一的分布式大数据处理分析引擎
- Spark特点:
- 速度快:在企业中应用:Spark会读取HDFS上数据、然后将数据加载内存中进行缓存,然后进行迭代计算,最后会将数据输出到HDFS之上或者其他外部存储设备。Spark是基于内存计算的大数据处理框架,数据缓存到内存中,能够重复里用。一般运行速度要比hadoop块100倍。
- 易用 (对开发者非常友好)
- Spark应用程序支持Scala、Java、Python、R、SQL
一站式解决不同的数据场景
- Spark的基础架构
- Spark Core (分析处理离线数据)
- Spark SQL (主要用来处理结构化或者半结构化数据的)
- SparkStreaming(主要用来做实时数据处理)
- MLlib (机器学习)
- Graphx (搞图计算)
- 一般在开发Spark应用程序的时候,可以同时使用以上不同的组件
- Spark的基础架构
- Spark具有很强的兼容性
- 能够运行在Hadoop之上、Yarn之上、Stanalone运行等等,能够兼容大部分大数据处理框架
3.Spark集群安装
- 说明:
- 集群:3台机器 名称 node-01 node-02 node-03
- 注意:
- 支持SSH
- 安装java JDK1.8
- Scala的安装:
- 安装步骤:
- 下载Scala 2.11.8 版本
- 将scala上传到虚拟机
- rz scala软件路径
- 规划scala安装目录 进行解压缩安装
- tar -zvxf scala-2.11.8.tgz
- mv scala-2.11.8 scala
- 配置环境变量
- export SCALA_HOME=scala安装目录
- PATH=$SCALA_HOME/bin
- source /etc/profile
- 验证scala安装是否成功
- scala -version
- 将安装同步到其他节点
- scp -r scala/ node-02:/home/soft/
- scp -r scala/ node-03:/home/soft/
- scp /etc/profile node-02:/etc/
- scp /etc/profile node-03:/etc/
- 安装步骤:
- 安装Spark集群
- 规划:node-01 为主节点 node-02 node-03 为从节点
- Spark版本 2.2.0
- 安装步骤
- 下载并且上传spark软件到node-01
- rz spark软件路径
- 规划安装目录 进行解压缩
- tar -zvxf spark-2.2.0-bin-hadoop2.7.tgz
- mvspark-2.2.0-bin-hadoop2.7 spark
- 配置spark的配置文件
- cp spark-env.sh.template spark-env.sh
vim spark-env.sh export SPARK_MASTER_HOST=node-01 export SPARK_MASTER_PORT=7077
- cp slaves.template slaves
vim slaves node-02 node-03
- cp spark-env.sh.template spark-env.sh
- 配置并生效环境变量
vim /etc/profile export JAVA_HOME=java安装路径 export SCALA_HOME=scala安装路径 export SPARK_HOME=SPARK安装路径 export path=:$SPARK_HOME\bin:$SPARK_HOME\sbin
- 同步spark安装目录以及环境变量配置文件到从节点
scp -r spark安装路径 node-02:spark的安装路径 scp -r spark安装路径 node-03:spark的安装路径 scp /etc/profile node-02:/etc/ scp /etc/profile node-03:/etc/
- 下载并且上传spark软件到node-01
4.启动和停止spark集群
- Spark集群启动
- cd spark/sbin
- ./start-all.sh
- 主节点:master进程 从节点 worker进程
- 如果集群启动异常 :第一要做就是查看日志
- Spark集群停止
- ./stop-all.sh
- 进程作用
- master进程:主要负责管理集群资源以及spark应用程序的运行的
- worker进程:主要负责提供计算资源(主要是cpu和内存、网络)
5.Spark UI介绍
- 访问地址:http://192.168.217.131:8080/
- 集群信息:
- URL: spark://node-01:7077 :主节点对外提供服务的接口
- Alive Workers: 存活的从节点数量
- Cores in use: 8 Total, 0 Used :所有worker节点的cpu核数 ,已使用的cpu核数
- Memory in use: 3.9 GB Total, 0.0 B Used:所有worker节点的内存,已使用的内存大小
- Applications:运行在spark集群上应用程序
- Status: ALIVE :进群的状态
- Workers worker节点列表
- workerId worker的IP地址以及服务端口 worker状态 worker提供的cpu个数 worker的内存大小
- 当前集群缺点:
- 只有一个master节点,如果master进程出现异常宕机,spark集群将不能够对外提供服务,所以需要备份机制,当master节点挂掉以后,备份机制会自动顶替master节点,以保证集群能够及时的对外提供服务
6.Spark高可用(HA)配置
- 前置条件:确保集群上zookeeper集群可用,并且正常启动
- 步骤:
vim spark-env.sh 注释: SPARK_MASTER_HOST 添加配置项: export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper. url=node-01:2181,node-02:2181,node-03:2181 -Dspark.deploy.zookeeper.dir=/spark" spark.deploy.recoveryMode:恢复模式。 spark.deploy.zookeeper.url: zookeeper节点信息 spark.deploy.zookeeper.dir:spark集群状态信息的存放位置
- 将spark-env.sh同步到其他worker节点
scp spark-env.sh node-02:/home/soft/spark/conf scp spark-env.sh node-03:/home/soft/spark/conf
- 在zookeeper配置项中任选两个或者三个节点启动master,其中一个master处于alive状态,其他master处于standby状态
7.Spark应用程序的运行
- 提交应用程序:bin/spark-submit 命令
--class 指定main函数的入口 --master spark程序运行时申请资源的入口 local[*] masater yarn jar文件路径 :应用程序jar class文件初始化参数 --executor-memory 20G 运行spark应用程序需要的每个节点上内存大小 --total-executor-cores 100 运行spark集群需要的总的cpu核数 spark 应用程序 如果不配置 executor-memory和 total-executor-cores 两个参数,默认使用集群上所有资源。
- 根据spark获取资源的方式不同,spark应用程序指定了不同的资源获取方法
--master local[N] 通过本地系统启动线程 模拟spark集群,运行spark应用程序 N 代表是启动线程的个数 N可以是* 代表的是cpu核数 ./spark-submit --class org.apache.spark.examples.SparkPi --master local[*] ../examples/jars/spark-examples_2.11-2.2.0.jar 100
standolone 模式 标准模式 --master spark://node-01:7077 spark集群的master节点 代表:向spark集群的master节点去申请资源。 --deploy-mode cluster/client 集群/客户端 :部署模式 代表的是在哪里驱动spark应用程序的运行 Driver程序 cluster:是在spark集群的任意节点去运行Driver程序(--class 类) client: 在哪里提交就在哪里启动Driver程序 ./spark-submit --class org.apache.spark.examples.SparkPi \ --master spark://node-01:7077,node-02:7077 \ ../examples/jars/spark-examples_2.11-2.2.0.jar 1000 注意:在spark master节点 切换过程中 并不影响已经正在运行的spark应用程序。 worker节点是spark应用程序真正执行的节点,spark-submit提交应用程序以后,会向master申请资源,当spark应用程序获取资源以后,就不会在于master通信,而是直接与worker节点进行通信。
yarn模式 运行spark应用程序 操作步骤: 第一步:配置spark配置文件:export HADOOP_CONF_DIR=XXX 第二步:同步spark配置文件 ./bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn \ --deploy-mode cluster \ --supervise \ --executor-memory 20G \ --total-executor-cores 100 \ /path/to/examples.jar \ 1000
8.开发Spark应用程序
8.1基于Spark-shell 开发spark应用程序
- spark-shell 是交互式窗口 编写spark应用程序
Spark context Web UI available at http://192.168.217.131:4040 主要是用来观察spark job任务执行情况的可视化界面 Spark context available as 'sc' (master = local[*], app id = local-1558447600912). 创建了SparkContext对象,对象名称sc。SparkContext是spark应用程序的唯一入口 SparkContext对象创建的时候 默认参数 master = local[*] appName Spark session available as 'spark'. 创建了SparkSession对象 名称spark。 主要是用来执行sparkSQL
- 基于spark-shell的wordcount
启动 :spark/bin/spark-shell --master 默认master local[*] //读取文件 val lineRDD=sc.textFile("文件路径") //切割每一行数据 val wordRDD=lineRDD.flatMap(_.split(" ")) // 标记每个单词 val wordPairRDD =wordRDD.map((_,1)) //统计 reduceByKey val wordCountRDD=wordPairRDD.reduceByKey(_+_) //输出打印 控制台 wordCountRDD.collect() //输出到 HDFS之上 wordCountRDD.saveAsTextFile("HDFS路径")
8.2 基于IDEA 开发Spark应用程序
package cn.itcast.spark import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} object SparkWordCount { def main(args: Array[String]): Unit = { System.setProperty("user","root") //构建SparkContext对象 val conf = new SparkConf() conf.setAppName("WordCount") conf.setMaster("local[*]") val sc = new SparkContext(conf) sc.setLogLevel("WARN") // 读取本地文件数据 val lineRDD: RDD[String] = sc.textFile("D:/aa.txt") //对每一行数据进行切分 val wordRDD: RDD[String] = lineRDD.flatMap((x: String) => x.split(",")) //对每一个单词进行标记 val wordPairRDD: RDD[(String, Int)] = wordRDD.map(word => (word, 1)) // 对具有相同key的单词进行统计 val wordCountRDD: RDD[(String, Int)] = wordPairRDD.reduceByKey((x: Int, y: Int) => x + y) //排序操作 参数: true 升序的 //val sortedRDD= wordCountRDD.sortBy(t=>t._2,true) val sortedRDD = wordCountRDD.map(t=>(t._2,t._1)).sortByKey().map(t=>(t._2,t._1)) /* //将数据汇总成Array val wordCountArray: Array[(String, Int)] = sortedRDD.collect() wordCountArray.foreach(t => println(t._1 + ":" + t._2)) */ //将数据保存在文件中 //sortedRDD.saveAsTextFile("D:/wordcount/") sortedRDD.saveAsTextFile("hdfs://node-01:9000/shenzhen/wordcount2/") } }
- 基于Java语言开发Spark应用程序
package cn.itcast.spark; 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; public class JavaSparkWC { public static void main(String[] args) { //创建SparkContext SparkConf conf = new SparkConf().setAppName("JavaSparkWC").setMaster("local[*]"); JavaSparkContext jsc = new JavaSparkContext(conf); jsc.setLogLevel("WARN"); //读取文件 JavaRDD<String> lineRDD = jsc.textFile("D:/aa.txt"); //切分每一行数据 JavaRDD<String> wordRDD = lineRDD.flatMap(new FlatMapFunction<String, String>() { /** * * @param s 代表一行一行的数据 * @return * @throws Exception */ @Override public Iterator<String> call(String s) throws Exception { String[] words = s.split(","); return Arrays.asList(words).iterator(); } }); //对每一个单词进行标记 JavaPairRDD<String, Integer> wordPairRDD = wordRDD.mapToPair(new PairFunction<String, String, Integer>() { /** * * @param s 代表一个一个单词 * @return * @throws Exception */ @Override public Tuple2<String, Integer> call(String s) throws Exception { return new Tuple2<String, Integer>(s, 1); } }); JavaPairRDD<String, Integer> wordCountRDD = wordPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() { @Override public Integer call(Integer v1, Integer v2) throws Exception { return v1 + v2; } }); //排序 JavaPairRDD<String, Integer> sortedRDD = wordCountRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() { @Override public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple2) throws Exception { return new Tuple2<Integer, String>(tuple2._2, tuple2._1); } }).sortByKey(true).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() { @Override public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple2) throws Exception { return new Tuple2<String, Integer>(tuple2._2, tuple2._1); } }); List<Tuple2<String, Integer>> list = sortedRDD.collect(); for (Tuple2<String, Integer> t : list) { System.out.println(t._1 + ":" + t._2); } } }
9.Spark程序运行过程中重要角色
- 从分配资源的角度
- ClusterManager:相当于master节点或者ResourceManager。SparkContext会向ClusterManager发送消息申请资源。ClusterManager接收到SparkContext的消息以后 会向workerNode节点发送消息,让workerNode汇报资源信息。ClusterManager会返回资源信息给SparkContext
- ClusterManager分配资源的方式:
- 静态分配:ClusterManager一次性分配好spark应用程序的所申请的全部资源
- 动态分配:ClusterManager 根据spark应用程序运行情况动态的分配资源 ,基于Yarn的运行都是动态分配。
- ClusterManager分配资源的方式:
- WorkerNode:主要是为spark应用程序提供资源(cpu和内存)。接受SparkContext消息并且启动Executor进程。并且会实时向SparkContext汇报其应用程序运行情况
- ClusterManager:相当于master节点或者ResourceManager。SparkContext会向ClusterManager发送消息申请资源。ClusterManager接收到SparkContext的消息以后 会向workerNode节点发送消息,让workerNode汇报资源信息。ClusterManager会返回资源信息给SparkContext
- 从程序运行的角度
- Driver:驱动程序 执行main 函数并且创建SparkContext对象。SparkContext是spark的主要入口。
- 执行spark-submit的节点
- spark集群中任意一个worker节点之上
- SparkContext:SparkContext是spark应用的主要入口。在SparkContext对象初始化过程中,创建Spark应用程序调度的三大核心对象:DAGScheduler(高层调度对象)、TaskScheduler(底层调度对象)、SchedulerBackend对象(调度对象的通信对象)
- Executor: 是在worker端启动的进程,该进程主要是用来运行Task的。实际上在Executor内部维护的是一个java线程池 (cache)。spark任务就是基于线程并发执行、或者线程复用的方式完成的
- Task:是spark中处理数据的最小单元。他最终会被封装成一个一个的线程任务TaskRunner。然后TaskRunner会直接放入线程池中,获取线程去执行
- cache :在Executor端 可以缓存RDD中数据。缓存以后的RDD数据能够被不同的Job任务复用,并且cache是Spark中重要容错机制
- Driver:驱动程序 执行main 函数并且创建SparkContext对象。SparkContext是spark的主要入口。