Structured Streaming
Structured Streaming 是 Spark Streaming 的进化版, 如果了解了 Spark 的各⽅⾯的进化过程, 有助于理
解 Structured Streaming 的使命和作⽤
\1. Spark 的 API 进化过程
\2. Spark 的序列化进化过程
\3. Spark Streaming 和 Structured Streaming
Spark 编程模型的进化过程
⽬标
Spark 的进化过程中, ⼀个⾮常重要的组成部分就是编程模型的进化, 通过编程模型可以看得出来内在的问题和
解决⽅案
过程
\1. 编程模型 RDD 的优点和缺陷
\2. 编程模型 DataFrame 的优点和缺陷
\3. 编程模型 Dataset 的优点和缺陷
分析 | 编程模型 |
---|---|
RDD | rdd.flatMap(.split(" "))<br /> .map((, 1)) <br /> .reduceByKey(_ + _) <br /> .collect <br /> 针对⾃定义数据对象进⾏处理, 可以处理任意类型的对象, ⽐较符合⾯向对象 <br /> RDD ⽆法感知到数据的结构, ⽆法针对数据结构进⾏编程 |
DataFrame | spark.read<br />.csv("...").<br />where( "age"=!="")<br />groupBy("age")<br />.show()<br />1. DataFrame 保留有数据的元信息, API 针对数据的结构进⾏处理, 例如说可以根据数据的某⼀列进⾏排序或者分组<br />2. DataFrame 在执⾏的时候会经过 Catalyst 进⾏优化, 并且序列化更加⾼效, 性能会更好<br />3. DataFrame 只能处理结构化的数据, ⽆法处理⾮结构化的数据, 因为 DataFrame 的内部使⽤ Row 对象保存数据<br />4. Spark 为 DataFrame 设计了新的数据读写框架, 更加强⼤, ⽀持的数据源众多 |
DataSet | spark.read<br />.csv("...")<br />.as[Person]<br />.where(.age!= "")<br />.groupByKey(.age)<br />.count()<br />.show()<br />1. Dataset 结合了 RDD 和 DataFrame 的特点,从 API 上即可以处理结构化数据, 也可以处理⾮结构化数据<br />2. Dataset 和 DataFrame 其实是⼀个东⻄, 所以 DataFrame 的性能优势, 在 Dataset 上也有 |
总结
RDD 的优点
\1. ⾯向对象的操作⽅式
\2. 可以处理任何类型的数据
RDD 的缺点
\1. 运⾏速度⽐较慢, 执⾏过程没有优化
\2. API ⽐较僵硬, 对结构化数据的访问和操作没有优化
DataFrame 的优点
\1. 针对结构化数据⾼度优化, 可以通过列名访问和转换数据
\2. 增加 Catalyst 优化器, 执⾏过程是优化的, 避免了因为开发者的原因影响效率
DataFrame 的缺点
\1. 只能操作结构化数据
\2. 只有⽆类型的 API , 也就是只能针对列和 SQL 操作数据, API 依然僵硬
Dataset 的优点
\1. 结合了 RDD 和 DataFrame 的 API , 既可以操作结构化数据, 也可以操作⾮结构化数据
\1. 既有有类型的 API 也有⽆类型的 API , 灵活选择
Spark 的 序列化 的进化过程
⽬标和问题
⽬标
Spark 中的序列化过程决定了数据如何存储, 是性能优化⼀个⾮常重要的着眼点, Spark 的进化并不只是针对
编程模型提供的 API , 在⼤数据处理中, 也必须要考虑性能
问题
\1. 序列化和反序列化是什么 ?
\2. Spark 中什么地⽅⽤到序列化和反序列化 ?
\3. RDD 的序列化和反序列化如何实现 ?
\4. Dataset 的序列化和反序列化如何实现 ?
什么是序列化和序列化?
序列化是什么
\1. 序列化的作⽤就是可以将对象的内容变成⼆进制, 存⼊⽂件中保存
\2. 反序列化指的是将保存下来的⼆进制对象数据恢复成对象
序列化对对象的要求
\1. 对象必须实现 Serializable 接⼝
\2. 对象中的所有属性必须都要可以被序列化, 如果出现⽆法被序列化的属性, 则序列化失败
限制
\1. 对象被序列化后, ⽣成的⼆进制⽂件中, 包含了很多环境信息, 如对象头, 对象中的属性字段等, 所以内容相
对较⼤
\2. 因为数据量⼤, 所以序列化和反序列化的过程⽐较慢
序列化的应⽤场景
\1. 持久化对象数据
\1. ⽹络中不能传输 Java 对象, 只能将其序列化后传输⼆进制数据
在 Spark 中的序列化和反序列化的应⽤场景
Task 分发
Task 是⼀个对象, 想在⽹络中传输对象就必须要先序列化
RDD 缓存
val rdd1 = rdd.flatMap(_.split(" ")) .map((_, 1)) .reduceByKey(_ + _) rdd1.cache rdd1.collect
RDD 中处理的是对象, 例如说字符串, Person 对象等
如果缓存 RDD 中的数据, 就需要缓存这些对象
对象是不能存在⽂件中的, 必须要将对象序列化后, 将⼆进制数据存⼊⽂件
⼴播变量
⼴播变量会分发到不同的机器上, 这个过程中需要使⽤⽹络, 对象在⽹络中传输就必须先被序列化
Shuffle 过程
Shuffle 过程是由 Reducer 从 Mapper 中拉取数据, 这⾥⾯涉及到两个需要序列化对象的原因
RDD 中的数据对象需要在 Mapper 端落盘缓存, 等待拉取
Mapper 和 Reducer 要传输数据对象
Spark Streaming 的 Receiver
Spark Streaming 中获取数据的组件叫做 Receiver , 获取到的数据也是对象形式, 在获取到以后需要落盘
暂存, 就需要对数据对象进⾏序列化
算⼦引⽤外部对象
class userserializable(i: Int) rdd.map(i => new Unserializable(i)) .collect .foreach(println)
在 Map 算⼦的函数中, 传⼊了⼀个 Unserializable 的对象
Map 算⼦的函数是会在整个集群中运⾏的, 那 Unserializable 对象就需要跟随 Map 算⼦的函数被传
输到不同的节点上
如果 Unserializable 不能被序列化, 则会报错
RDD 的序列化
RDD 的序列化
RDD 的序列化只能使⽤ Java 序列化器, 或者 Kryo 序列化器
为什么?
RDD 中存放的是数据对象, 要保留所有的数据就必须要对对象的元信息进⾏保存, 例如对象头之类的 保存⼀ 整个对象, 内存占⽤和效率会⽐较低⼀些
Kryo 是什么
Kryo 是 Spark 引⼊的⼀个外部的序列化⼯具, 可以增快 RDD 的运⾏速度 因为 Kryo 序列化后的对象
更⼩, 序列化和反序列化的速度⾮常快 在 RDD 中使⽤ Kryo 的过程如下
val conf = new SparkConf() .setMaster("local[2]") .setAppName("KyroTest") conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") conf.registerKryoClasses(Array(classOf[Person])) val sc = new SparkContext(conf) rdd.map(arr => Person(arr(0), arr(1), arr(2)))
DataFrame 和 Dataset 中的序列化
历史的问题
RDD 中⽆法感知数据的组成, ⽆法感知数据结构, 只能以对象的形式处理数据
DataFrame 和 Dataset 的特点
DataFrame 和 Dataset 是为结构化数据优化的
在 DataFrame 和 Dataset 中, 数据和数据的 Schema 是分开存储的
spark.read .csv("...") .where($"name" =!= "") .groupBy($"name") .map(row: Row => row) .show()
DataFrame 中没有数据对象这个概念, 所有的数据都以⾏的形式存在于 Row 对象中, Row 中记录了每
⾏数据的结构, 包括列名, 类型等
Dataset 中上层可以提供有类型的 API , ⽤以操作数据, 但是在内部, ⽆论是什么类型的数据对象 Dataset 都使
⽤⼀个叫做 InternalRow 的类型的对象存储数据
val dataset: Dataset[Person] = spark.read.csv(...).as[Person]
总结
\1. 当需要将对象缓存下来的时候, 或者在⽹络中传输的时候, 要把