spark总结

spark

一、了解spark

1.离线分析

  • 把一段时间的数据经过收集,整理,分析,得出一定的结论

  • 这个结论会帮助人们做一些决策

  • 不要求时限性

  • 对数据的处理方式:批处理

2.实时分析

  • 必须要求时效性,数据实时产生,实时处理

  • 对数据的处理方式:流处理

3.spark

  • 对于大规模数据处理的一个快如闪电的统一的分析引擎(计算框架)

  • 作者:美国加州大学伯克利分校AMP(A:算法,M:机器,P:人)实验室

  • 通过对算法,机器和人的大规模整合来展现大数据的应用

(2) 特点:

  • 速度快:基于内存spark比MR快100X,即使用磁盘快10X

    ​ 原因:基于内存;DAG有向无环图

  • 易用性:

    支持scala,java,python,R,SQL语言(spark源码scala)

    支持scala,python,R和SQL的shell操作

    提供了超过80种的高级操作(算子)

  • 可用性:

    可以在一个应用程序中无缝整合所有的组件

    sparkCore:spark在没有特别指定的前提下,就是sparkCore,是spark的核心计算引擎

    sparkSQL:使用SQL处理结构化数据的组件

    sparkStreaming:处理实时的流式数据,进行实时分析的组件

    ​ 伪实时的计算框架,使用的是微批次处理的方式

    sparkR:支持R语言的组件

    MLib:Machine Learning library 机器学习算法库

    GraphX:支持图计算

  • 运行在任何地方

    可以在任何环境下执行:local(windows/linux) standalone onYarn

    可以接收各种数据源

4.RDD

  • 弹性的分布式的数据集。是spark的核心。是计算过程中产生的瞬时结果。

  • 弹性的:局部发生一些变化但不会对整体产生影响

  • 分布式:数据集本身与分布式没有关系

    ​ 是数据集内部的数据可以存储和计算

  • 数据集:数据的集合

(1) 特点:

五个特性:

  • 一组分组的集合

  • 一个函数作用于所有的切片

  • rdd依赖于其他的rdds

  • 可以重新分区

  • 数据的本地性,本地数据优先在本地计算

总结特性:

  • 是不可变的

  • 可以并行计算

  • 每个rdd的输入是上一个rdd的输出

  • spark的代码本质都是一个DAG有向无环图

  • rdd是一个抽象的概念

5.容错机制

  • 如果某个位置出现错误,首先根据DAG有向无环图查找依赖关系

  • 根据依赖关系向父级依赖查找数据,如果父级rdd做了持久化

  • 可以直接从父级rdd获取数据,计算父级RDD以下的计算过程

  • 如果父级RDD没做持久化,继续向上查找,直到找到有数据的RDD为止

  • 最坏的结果就是从HDFS重新读取数据重新计算,

  • 如果达到了一定的时间阈值还没有计算出结果,spark会重新启动一个任务

  • 原任务不停止,哪个先算出来,用哪个结果

6.算子

官方网站:高级操作

俗称:算子

本质:函数

区别:

​ 普通的集合.调用的就是函数

​ RDD.调用的就是算子

分类:

​ 转换算子(transformation)

​ 用代码描述整个业务逻辑,但是不提交任务,不执行

​ 可以从sc读取原数据创建出一个RDD或者从已有RDD转成另一个RDD

​ a.创建算子

​ 从sc读取原数据创建出一个RDD的算子

​ textFile

​ wholeTextFiles

​ parallelize

​ makeRdd

​ b.缓存算子

​ 对某个RDD做持久化

​ cache

​ persist

​ checkpoint

​ 行动算子(action)

​ 逻辑描述完毕,提交任务,执行任务,得到结果。

​ 一个任务内只能有一个action算子,不允许重复调用

常见的算子

1.行动算子

collectAsMap:相当于map操作,去掉键相同的键值对

  //如果RDD中同一个Key中存在多个Value,那么后面的Value将会把前面的Value覆盖,
  //最终得到的结果就是Key唯一,而且对应一个Value。

count:计数,返回rdd中的元素数量

countByKey:用来统计RDD[k,v]中每个k的数量

countByValue:统计出集合中每个元素的个数

first:返回RDD中的第一个元素,不排序。

reduce:对集合中的数依次进行相关计算。比如说连加,阶乘

saveAsTextFile

  val list = List(1,3,5,2,4)
​
  val rdd = sc.parallelize(list,3)
​
  //将数据集的元素,以textfile的形式保存到本地文件系统hdfs或者任何其他hadoop支持的文件系统,
  //spark将会调用每个元素的toString方法,
  //并将它转换为文件中的一行文本
  rdd.saveAsTextFile("D://test2")
​
  //使用java的序列化方法保存到本地文件,可以被sparkContext.objectFile()加载
  rdd.saveAsObjectFile("D://test1")

take:用于获取RDD中从0到num-1下标的元素,不排序。

takeSample:有无放回抽样,可控制返回元素个数

​ 详细见:RDD算子之sample、takeSample源码详解_木凡空的博客-CSDN博客_rdd sample

top:用于从RDD中,按照默认(降序)或者指定的排序规则,返回前num个元素。

takeOrdeed:和top类似,只不过和top相反的顺序返回元素

2.转换算子

cartesian:两个RDD进行笛卡尔积合并

coalesce:用于将RDD进行重分区,使用HashPartitioner

​ 且该RDD的分区个数等于numPartitions个数

​ 如果shuffle设置为true,则会进行shuffle

cogroup:对多个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合。

​ 与reduceByKey不同的是针对两个RDD中相同的key的元素进行合并。

distinct:将原始RDD中重复出现的元素进行过滤,返回一个新生成的RDD

filter:对元素进行过滤,对每个元素应用f函数,返回值为true的元素在RDD中保留,返回为false的将过滤掉

flatMap: map的变换操作是对原RDD中的每个元素进行一对一的操作,生成的RDD中元素的数量与原RDD

​ 中元素数量相同,但flatMap可以将每个元素进行一对多的变换操作

groupByKey:将Key/Value型的RDD中的元素按照Key值进行汇聚,Key值相同的Value值会合并为一个序列。

intersection:返回两个RDD的交集

map:将原来RDD的每个数据项通过map中的用户自定义函数f映射转变为一个新的元素

mapValues:同基本转换操作中的map,针对[K,V]中的V值进行map操作。

reduceByKey:针对RDD中相同的key的元素进行合并

sample

  val list = List(1,2,3,4,5,6,7,8,9,10)
  val rdd = sc.parallelize(list)
  rdd.sample(true,0.5,System.currentTimeMillis).foreach(println)
​
  val rdd1 = sc.parallelize(Range(1,101).toList)
​
  //对RDD进行抽样,其中参数withReplacement为true时表示抽样之后还放回,可以被多次抽样,
  //false表示不放回;fraction表示抽样比例;seed为随机数种子,比如当前时间戳
  rdd1.sample(true, 0.1,System.currentTimeMillis()).foreach(println)

sortByKey:通过key进行排序,false为降序,ture为升序

subtract:返回RDD中出现,并且不在otherRDD中出现的元素,不去重。

subtractByKey:返回key在RDD中出现,并且不在otherRDD中出现的元素,不去重。

union:合并两个RDD,不去重

value:获取所有的value

zip:用于将两个RDD组合成Key/Value形式的RDD,这里默认两个RDD的partition数量以及元素数量都相同,

​ 否则会抛出异常。

7.并行度

(1) textFile

​ 可以读取单独的文件数据,也可以读取整个路径下的所有文件数据

​ 把所有文件一一个文件的形式进行处理。

​ 如果指定并行度,直接使用

​ 如果没有指定并行度,走默认的最小分区数

​ 最小分区数 = math.min(默认并行度,2)

​ 默认并行度:

​ a.如果设置了 spark.default.parallelism 直接读取

​ b.如果没设置

​ ①本地模式:当前节点的cpu总核心数

​ ②独立模式:适用父类(分布式)的方式

​ ③分布式模式:当前集群中所有节点的所有cpu的核心数与2的最大值

​ 分区策略与hadoop的FileInputFormat一致

(2) wholeTextFiles

​ 可以读取单独的文件的数据,也可以读取整个路径的所有文件数据

​ 每个文件以一个键值对(二元组)的形式保持一致

​ key为文件的路径

​ value为文件的内容

​ 分区数量与textFile的形式保持一致

​ 分区策略与hadoop的CombineFileInputFormat一致

(3) parallelize

​ 把已知集合创建成RDD类型

​ 可以指定分区的数量

​ 如果没有指定分区数量,走默认并行度

(4) makeRdd

​ 如果参数与parallelize一样,执行的就是paralleize方法

​ 如果参数是Seq[(T,Seq[String])]这个泛型,这个集合中的每个元素分别为一个独立分区。

8.持久化

  • 在java中,把数据写入数据库的过程

  • 在spark中,把RDD临时永久地写入到节点地某个位置(磁盘或内存)

    永久:避免当前RDD被当作垃圾回收掉,对其永久保存

    临时:即使做了持久化,在内存中也不是绝对地安全

    ​ a.由于某种特殊情况,会被当作垃圾回收掉

    ​ b.没有意外情况下,根据LRU也会被当作垃圾回收掉

  • 容错机制

    如果持久化的数据丢失了,spark会自动从HDFS上找数据重新计算到这个位置,自动持久化。

  • 使用

    缓存算子:

    cache persist

    这两个算子完全等价

    相当于使用了默认的的仅用内存的持久化策略

    RDD.cache() / persist()

    RDD.persist(StorageLevel.XXX)

    移除持久化:

    a.根据LRU自动取消持久化

    b.RDD.unpersist()

  • 验证:

    ​ a.webUI http://ip:4040 -> storage

    ​ b.RDD.getStorageLevel 以StorageLevel对象的类型返回

    ​ RDD.getStorageLevel.describe 以字符串类型返回

策略

(1) MEMORY_ONLY 与 MEMORY_AND_DISK对比

​ MEMORY_ONLY:先可内存存储,存不下就不存了。读取数据的时候先读内存,没有持久化的部分从HDFS重

​ 新计算

​ MEMORY_AND_DISK:先可内存存储,如果存不下,就存磁盘

总结:

作者认为,即使从hdfs重新计算也比多做一次磁盘IO速度快

使用场景:

  • 如果没有特殊情况,直接使用默认的存储等级

    这种情况可以使用CPU发挥最大的性能

  • 如果内存不太充足,可以选择SER,节省一定的空间

    由于还是内存计算,速度也会快,但是读取的时候需要反序列化

  • 除非计算很复杂不要使用DISK

    重新计算的耗时与做磁盘IO差不多甚至更多,可以选择此方式

  • 如果想做快速恢复可以使用带副本的形式

    虽然可以自动容错,但是重新计算需要时间

checkPoint()

  • 把当前RDD可以标记成一个检查点

  • 把当前RDD的最终状态保存到一个目录中,目录由sc.setCheckPointDir设置

  • 会移除当前RDD的所有父级依赖的引用,它成为了顶级依赖

  • 这是个转换算子,必须在行动算子之前调用

  • 强烈建议在检查点之前先设置persist,避免重复计算

9.宽窄依赖

(1) 窄依赖(父到子一对一)narrowDependency:

​ 父级RDD里的每一个partition对应子级RDD里的唯一一个partition的关系

(2) 宽依赖(父到子一对多)shuffleDependency:

​ 父级RDD里的每一个partition对应子级RDD里的多个partition的关系,一定要执行shuffle操作

10.shuffle

详细文档:Spark中的Spark Shuffle详解 - 大葱拌豆腐 - 博客园

(1) HashShuffle(1.2版本之前默认使用)

​ 普通机制:产生的文件数量是 M*R,小文件太多

​ 合并机制:产生的文件数量是 Core*R,比普通机制少,但是也是很多

(2) SortShuffle(1.2版本之后默认使用)

​ 普通机制:每个task产生一个磁盘文件

​ 由于数据都在里面,另有一个索引文件。

​ 需要排序

​ byPass机制:如果task数量小于等于阈值(默认200),使用此机制

​ 不需排序,节省了性能

二、sparkSQL

  • 处理结构化数据的组件

  • 计算过程是DataSet与DataFrame之间的转换(与RDD类似)

  • DS/DF可以创建出来,也可以由其他DS/DF转换而来

  • DS:数据集合

  • DF:数据框架(比DS多了schema)

1.使用

(1) 创建sparkSession

​ val spark:SparkSession = SparkSession.builder()

​ .master(xxx)

​ .appName(xxx)

​ .config(key,value)

​ ......

​ .getOrCreate()

(2) 读写数据

读:

​ //没有格式化的情况,默认使用parquet格式

​ spark.read.format(type).load(path)

​ //读数据的简化形式

​ spark.read.type(path)

写:

​ //没有格式化的情况,默认使用parquet格式

​ df.write. format(type).save(path)

​ //写数据的简化情况

​ df.write.type(path)

(3)保存模式

​ a.ErrorIfExists 默认情况,如果存在就报错

​ b.Append 追加 向目标目录中添加一个新文件

​ c.Overwrite 覆盖

​ d.Ignore 忽略,如果存在不报错

​ 两种实现方式

​ a.df.write.mode("")

​ b.df.write.mode(SaveMode.xxx)

(4) 数据分析

​ a.DataSetAPI

​ DataSet可以通过调用函数的形式对数据进行分析

​ 只要sql中可以支持的操作,API都有相应的与之对应

​ API可以进行链式调用(多个条件)

​ 可以使用$“字段”获取相应内容,前提必须引入隐式转换

​ b.SQL

​ 把所有的操作都交给sql完成

​ sql语法不与任何一种sql语法完全一样

​ 四种创建临时视图的方式:

​ 1) createTempView 当前session有效,存在报错

​ 2) createOrReplaceTempView 当前session有效,存在替换

​ 3) createGlobalTempView 所有session有效,存在报错

​ 4) createOrReplaceGlobalTempView 所有session有效,存在替换

​ 创建持久化表

​ 相当于写文件与创作表的整合

​ df.write.option("path","xxx").saveAsTable(tableName)

​ 可以直接读取文件数据

​ spark.sql("select * from type.‘path’)

(5)几种转换关系

①普通集合转DS/DF

​ 语法:

​ 集合.toDS()

​ 集合.toDF()

​ 集合.toDF(列名*)

​ 注意:

​ 使用任何一种形式都必须先引入隐士转换

​ toDS和toDF无参两种情况结果一样但是类型不一样

​ 如果需要表头,必须使用toDF(xxx),列名的个数和顺序必须与集合中的数据一致

​ 如果想创建一个多列的数据,需要使用元组的形式

②RDD转成DS/DF

  • 语法与普通集合转DS/DF一致

  • RDD比普通集合更灵活一些,可以把每条数据转换成元组或类的实例化对象

  • 通过反射机制推断出schema(表名和类型)

③RDD转成DS/DF,人为设计schema

​ 可以由开发人员自己控制每个字段的各种属性

​ 三个步骤:

​ 1)创建原始RDD,并转成row类型

​ 2)设计每个字段,形成schema

​ 3)最后进行合并,创建DF

④DF/DS转成RDD

​ DS/D.rdd

​ RDD和DF/DS之间可以随意转换,无缝整合

​ 注意:DF/DS转成rdd之后是ROW类型的数据

(6) 读取hive仓库的数据

  • sparkSQL可以读取hive仓库的数据

  • 如果使用hive,必须在sparkSession中添加hive的支持

  • 语法与hive语法一致

  • warehouse和元数据库的三种形式:

    没有任何设置,在当前项目路径下创建derby元数据库和数据仓库

    可以指定数据仓库位置

    可以通过hive-site.xml改变元数据库

spark on hive 和 hive on spark 的区别:

​ spark on hive :

​ hive只作为存储角色,spark 负责sql解析优化,底层运行的还是sparkRDD

​ 具体可以理解为spark通过sparkSQL使用hive语句操作hive表,底层运行的还是sparkRDD,步骤如下:

​ 1.通过sparkSQL,加载Hive的配置文件,获取Hive的元数据信息

​ 2.获取到Hive的元数据信息之后可以拿到Hive表的数据

​ 3.通过sparkSQL来操作Hive表中的数据

​ hive on spark:

​ hive既作为存储又负责sql的解析优化,spark负责执行

​ 这里Hive的执行引擎变成了spark,不再是MR。

​ 这个实现较为麻烦,必须重新编译spark并导入相关jar包

​ 目前大部分使用spark on hive

(7) jdbc

(1) 读:

​ 普通方式:

​ spark.read.option("url").option("dbtable").option("user").option("password").load()

​ 简便方式:

​ spark.read.jdbc(url,dbtable,prop)

(2) 写:

​ 普通方式:

​ spark.write.option("url").option("dbtable").option("user").option("password").save()

​ 简便写法:

​ spark.write.jdbc(url,dbtable,prop)

注意:

  • 写数据得时候可以使用savemode

  • 简便写法的properties可以共用,比较简单

  • 不管是读还是写,都需要指定到表级别

  • 关于写入数据的几种情况

    如果新数据的字段是原数据字段的子集,可以正常追加

    如果新数据的字段不是原数据字段的子集,不能追加

    任何情况,都可以以覆盖的形式写入(重新建表)

(8)分区,分桶,排序

分区:以目录级别进行划分

分桶:以文件级别进行划分

分桶和排序必须使用saveAsTable,分区可以使用save和savaAsTable

(9)scheme合并

在parquet文件中,可以先定义少部分schema,

根据实际需求,可以添加更多的schema

但是需要开启 mergeSchema -> true

三、sparkStreaming

  • 处理实时流数据的组件

  • 伪实时的计算框架,使用的是微批次处理方式

1.数据处理的过程

a.获取实时的流失数据(源源不断产生的数据源)

b.接收到的实时数据实际上是按照时间间隔为一个批次进行切割

每个微批次的数据本质就是一个RDD

c.由sparkCore引擎执行每个RDD的内容

d.把最终的结果数据写入到某个位置

2.DStream

  • 一个离散化的数据流,是一个高级抽象,是RDD的集合

  • 可以由原数据创建而来,也可以通过算子转换成另一个DStream

  • DStream之间的转换实际上就是里面的每个RDD之间的转换

3.三个组件的对比

组件名操作对象中间过程
sparkCoresparkContextRDD
sparkSQLsparkSessionDF/DS
sparkStreamstreamingContextDstream

4.编码过程

①创建ssc(可以通过conf,也可以通过sc)

②读取原数据,创建Dstream

③使用transformation算子和output算子转换和输出DStream

④ssc.start() 开启接受数据和处理数据

⑤ssc.awaitTermination() 等待程序的终止(手动关闭或程序错误)

⑥实时处理一般不关闭服务,如果需要关闭,可以使用 ssc.stop()

注意:

  • 同一时间内一个JVM只能运行一个ssc,且一旦关闭,不会自动重启

  • 如果关闭了ssc.sc也一起被关闭

    如果不想关闭sc,可以通过stop(stopSparkContext = false)

  • sparkStreaming需要至少两个core来处理业务(一个接收数据,其余处理数据)

5.算子

(1) transformation算子

transform

①对数据中的每个RDD进行处理,RDD不需要调用action算子

②直接以RDD类型返回。最终还是以DStream形式接收

③与map算子的区别

map也是DStream级别调用,但是函数是以数据级别进行操作

updateStateByKey

状态:到某个时间点为止的综合所有数据的最终状态

有状态:计数,求和,统计。。。。

无状态:来了就走,跟其他批次数据没有任何关系。

window

对一定时间范围的数据进行整合处理

两个参数:

①窗口长度:以时间为长度,是时间间隔的整数倍

②滑动间隔:以时间为长度,是时间间隔的整数倍

控制每隔多长时间读取一次窗口的数据,允许有数据的交叉

(2)join

output算子

foreachRDD:

对每个RDD级别做处理,是output算子,没有返回值

与transform算子做对比:

也是对每个RDD级别做处理,是transformation算子,有返回值

在内部的RDD以action算子输出结果

DataFrame&SQL算子

  • 可以读取实时数据,然后对RDD级别进行操作

  • 可以把RDD转换成DS/DF执行执行sparkSQL操作

  • 实现了各组件之间的无缝整合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值