Apache Spark 的数据存储优化
本文介绍了用于优化数据存储以在 Azure HDInsight 上高效执行 Apache Spark 作业的策略。
概述
Spark 支持多种格式,比如 csv、json、xml、parquet、orc 和 avro。 Spark 可以借助外部数据源进行扩展,以支持更多格式 — 有关详细信息,请参阅 Apache Spark 包。
最能提高性能的格式是采用 Snappy 压缩的 Parquet,这是 Spark 2.x 中的默认格式。 Parquet 以分列格式存储数据,并在 Spark 中得到了高度优化。
选择数据抽象
早期的 Spark 版本使用 RDD 提取数据,Spark 1.3 和 1.6 分别引入了 DataFrame 和 DataSet。 请仔细衡量下列优缺点:
- DataFrame
- 大多数情况下的最佳选择。
- 通过 Catalyst 提供查询优化。
- 全阶段代码生成。
- 直接内存访问。
- 垃圾回收 (GC) 开销低。
- 不像数据集那样易于开发者使用,因为没有编译时检查或域对象编程。
- DataSet
- 适合可容忍性能受影响的复杂 ETL 管道。
- 不适合需要考虑性能受影响的聚合。
- 通过 Catalyst 提供查询优化。
- 提供域对象编程和编译时检查,适合开发。
- 增加序列化/反序列化开销。
- GC 开销高。
- 中断全阶段代码生成。
- RDD
- 不必使用 RDD,除非需要生成新的自定义 RDD。
- 不能通过 Catalyst 提供查询优化。
- 不提供全阶段代码生成。
- GC 开销高。
- 必须使用 Spark 1.x 旧版 API。
选择默认存储
创建新的 Spark 群集时,可以将 Azure Blob 存储或 Azure Data Lake Storage 用作群集的默认存储。 这两个选项都具有可长期存储暂时性群集的优势。 这样,在删除群集时,就不会自动删除数据。 用户可以重新创建暂时性群集,并且依然能访问数据。
存储类型 | 文件系统 | Speed | 暂时性 | 用例 |
---|---|---|---|---|
Azure Blob 存储 | wasb: //url/ | 标准 | 是 | 暂时性群集 |
Azure Blob 存储(安全) | wasbs: //url/ | 标准 | 是 | 暂时性群集 |
Azure Data Lake Storage Gen 2 | abfs: //url/ | 较快 | 是 | 暂时性群集 |
Azure Data Lake Storage Gen 1 | adl: //url/ | 较快 | 是 | 暂时性群集 |
本地 HDFS | hdfs: //url/ | 最快 | 否 | 全天候交互型群集 |
使用缓存
Spark 提供自己的本机缓存机制,可通过各种方法(比如 .persist()
、.cache()
和 CACHE TABLE
)使用。 这种本机缓存适用于小型数据集以及需要缓存中间结果的 ETL 管道。 但是,Spark 本机缓存目前并非很适用于分区,因为缓存表不保留分区数据。 存储层缓存是一种更通用且更可靠的缓存技术。
本机 Spark 缓存(不推荐)
- 适用于小型数据集。
- 不可用于分区,但将来的 Spark 版本可能会实现这一点。
存储级缓存(推荐)
- 可以在 HDInsight 上使用 IO 缓存功能实现。
- 使用内存中和 SSD 缓存。
本地 HDFS(推荐)
hdfs://mycluster
路径。- 使用 SSD 缓存。
- 删除群集时,缓存数据将丢失,需要重新生成缓存。
优化数据序列化
Spark 作业是分布式作业,因此,适当的数据序列化对实现最佳性能很重要。 Spark 有两个序列化选项:
- Java 序列化是默认选项。
Kryo
序列化是一种较新的格式,可带来比 Java 更快、更紧凑的序列化。Kryo
要求在程序中注册类,并且尚不支持所有的可序列化类型。
使用 Bucket 存储
Bucket 存储类似于数据分区。 但每个 Bucket 都可以保存一组列值,而不只是一个列值。 此方法非常适合对大量(数以百万计或更多)值(比如产品标识符)分区。 通过哈希行的 Bucket 键可以确定 Bucket。 由 Bucket 存储的表可提供独一无二的优化,因为它们存储了有关其 Bucket 存储方式和排序方式的元数据。
下面是一些高级 Bucket 存储功能:
- 基于 Bucket 存储元信息的查询优化。
- 优化的聚合。
- 优化的联接。
可以同时使用分区和 Bucket 存储。