Spark入门基础

7 篇文章 3 订阅
3 篇文章 0 订阅

为什么使用Spark

MapReduce编程模型的局限性
繁杂

  • 只有Map和Reduce两个操作,复杂的逻辑需要大量的样板代码

处理效率低

  • Map中间结果写磁盘,Reduce写HDFS,多个Map通过HDFS交换数据
  • 任务调度与启动开销大

不适合迭代处理、交互式处理和流式处理
Spark是类Hadoop MapReduce的通用并行框架
Job中间输出结果可以保存在内存,不再需要读写HDFS
比MapReduce平均快10倍以上

Spark的优势

速度快
基于内存数据处理,比MR快100个数量级以上(逻辑回归算法测试)
基于硬盘数据处理,比MR快10个数量级以上
易用性
支持Java、Scala、Python、R语言
交互式shell方便开发测试
通用性
一栈式解决方案:批处理、交互式查询、实时流处理、图计算及机器学习
随处运行
YARN、Mesos、EC2、Kubernetes、Standalone、Local

Spark技术栈

在这里插入图片描述
Spark Core:核心组件,分布式计算引擎
Spark SQL:高性能的基于Hadoop的SQL解决方案
Spark Streaming:可以实现高吞吐量、具备容错机制的准实时流处理系统
Spark GraphX:分布式图处理框架
Spark MLlib:构建在Spark上的分布式机器学习库

spark运行框架

在这里插入图片描述

  • 在驱动程序中,通过SparkContext主导应用的执行
  • SparkContext可以连接不同类型的Cluster
    Manager(Standalone、YARN、Mesos),连接后,获得集群节点上的Executor
  • 一个Worker节点默认一个Executor,可通过SPARK_WORKER_INSTANCES调整
  • 每个应用获取自己的Executor
  • 每个Task处理一个RDD分区
术语说 明
Application建立在Spark上的用户程序,包括Driver代码和运行在集群各节点Executor中的代码
Driver program驱动程序。Application中的main函数并创建SparkContext,Spark中有SparkContext负责与Cluster Manager通信,进行资源申请、任务的分配和监控等,当Executor部分运行完毕后,Driver同时负责将SparkContext关闭
Cluster Manager在集群(Standalone(park原生的资源管理,由Master负责资源的分配)、Mesos(与hadoop MR兼容性良好的一种资源调度框架)、YARN(主要是指Yarn中的ResourceManager))上获取资源的外部服务
Worker Node集群中任何可以运行Application代码的节点
Executor某个Application运行在worker节点上的一个进程
Task被送到某个Executor上的工作单元
Job包含多个Task组成的并行计算,往往由Spark Action触发生成,一个Application中往往会产生多个Job
Stage每个Job会被拆分成多组Task,作为一个TaskSet,其名称为Stage

当执行一个Application时,Driver会向集群管理器申请资源,启动Executor,并向Executor发送应用程序代码和文件,然后在Executor上执行Task,运行结束后,执行结果会返回给Driver,或者写到HDFS或者其它数据库中。

Spark两个重要的类

SparkContext

import org.apache.spark.{SparkConf, SparkContext}
val conf=new SparkConf().setMaster("local[2]").setAppName("HelloSpark")
val sc=SparkContext.getOrCreate(conf)
//aa.txt
/**
hello world
hello spark
*/
sc.textFile("file:///d:/aa.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).foreach(println)//分词统计
sc.stop()
//结果
//(spark,1)
//(hello,2)
//(world,1)

SparkSession

val spark = SparkSession.builder().master("local[*]").appName("mytab").getOrCreate()
val tab1 = spark.read.format("csv").option("header","true").load("file:///D:/notepad++/File/hadoop/hive/testmonday/customer_details.csv")
   tab1.createOrReplaceTempView("customer_details")
   spark.sql("select * from userinfos").show(false)

Spark API

RDD
Spark核心,主要数据抽象
Dataset
从Spark1.6开始引入的新的抽象,特定领域对象中的强类型集合,它可以使用函数或者相关操作并行地进行转换等操作
DataFrame
DataFrame是特殊的Dataset

Spark RDD概念

简单的解释
RDD是将数据项拆分为多个分区的集合,存储在集群的工作节点上的内存中,并执行正确的操作
复杂的解释
RDD是用于数据转换的接口,指向了存储在HDFS、Cassandra、HBase等、或缓存(内存、内存+磁盘、仅磁盘等),或在故障或缓存收回时重新计算其他RDD分区中的数据

RDD是弹性分布式数据集(Resilient Distributed Datasets
分布式数据集
RDD是只读的、分区记录的集合,每个分区分布在集群的不同节点上
RDD并不存储真正的数据,只是对数据和操作的描述
弹性
RDD默认存放在内存中,当内存不足,Spark自动将RDD写入磁盘
容错性
根据数据血统,可以自动从节点失败中恢复分区
DAG:有向无环图,反映了RDD之间的依赖关系
在这里插入图片描述
RDD的特性

  • 一系列的分区(分片)信息,每个任务处理一个分区
  • 每个分区上都有compute函数,计算该分区中的数据
  • RDD之间有一系列的依赖
  • 分区函数决定数据(key-value)分配至哪个分区
  • 最佳位置列表,将计算任务分派到其所在处理数据块的存储位置

RDD的创建

parallelize使用集合创建RDD

//使用集合创建RDD
val rdd=sc.(List(1,2,3,4,5,6))
rdd.count
rdd.partitions.size
val rdd=sc.parallelize(List(1,2,3,4,5,6),5)
rdd.partitions.size
val rdd=sc.makeRDD(List(1,2,3,4,5,6))
//1、Spark默认会根据集群的情况来设置分区的数量,也可以通过parallelize()第二参数来指定
//2、Spark会为每一个分区运行一个任务进行处理
object MySparkRDD {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[2]").setAppName("myjob")
    val sc = new SparkContext(conf)
    //并行计算的速度----核数
    //并行计算的粒度----分区数量
    //一个分区就是一个task,分片最后决定任务数量
    val rdd = sc.parallelize(List(1,2,3,5,4,6,7,8),2)//开了多核,但是只有一个核在工作
//    val rdd = sc.parallelize(List((1,1),(2,1),(3,1),(4,1)),2)
    //foreach遍历所有,但是是一个一个处理
    //foreachPartition每一个片遍历,但是是同时进行
    println("============================默认Range分区======================================")
    rdd.foreachPartition(f=>println(f.toList))
    println("============================设置分区数,(K,V)型=================================")
    //用map转成(K,V)型
    rdd.map((_,1)).groupByKey(2).foreachPartition(f=>println(f.toList))
    println("============================自定义分区方式partitionBy===========================")
    //必须是(K,V)型,才能调出partitionBy()方法
    rdd.map((_,1)).partitionBy(new MyPartition(3)).foreachPartition(f=>println(f.toList))
    println("============================设置分区方式========================================")
//    val rdd = sc.parallelize(List(1,2,3,5,4,6,7,8),2).repartition(1)//设置分区方式
    rdd.map((_,1)).foreachPartition(f=>println(f.toList))
    //rdd.coalesce(num,boolean)
    //rdd.persist()
    //val e = rdd.map((_,1)).cache()缓存,最好用新节点记录一下(读文件加cache)
  }
}

通过加载文件产生RDD

val distFile=sc.textFile("file:///home/hadoop/data/hello.txt")
object ReadTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("cust")
    val sc = new SparkContext(conf)
    val rdd = sc.textFile("file:///d:/notepad++/File/hadoop/scala/customers.csv")
//    rdd.foreach(println)
    sc.stop()
  }
}

其他创建RDD的方法
SparkContext.wholeTextFiles():可以针对一个目录中的大量小文件返回<filename,fileContent>作为PairRDD
SparkContext.sequenceFile[K,V]():Hadoop SequenceFile的读写支持
SparkContext.hadoopRDD()、newAPIHadoopRDD():从Hadoop接口API创建
SparkContext.objectFile():RDD.saveAsObjectFile()的逆操作

RDD分区

分区是RDD被拆分并发送到节点的不同块之一
拥有的分区越多,得到的并行性就越强
每个分区都是被分发到不同Worker Node的候选者
每个分区对应一个Task
在这里插入图片描述
RDD的操作
分为lazy与non-lazy两种
Transformation(lazy):也称转换操作、转换算子
1、仅记录作用于RDD上的操作
2、当遇到动作算子(Action)时才会进行真正计算
在这里插入图片描述
Actions(non-lazy):也称动作操作、动作算子
当程序遇到动作算子立即执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值