0%

简介

Hive作为Hadoop家族历史最悠久的组件之一,一直以其优秀的兼容性支持和稳定性而著称,越来越多的企业将业务数据从传统数据库迁移至Hadoop平台,并通过Hive来进行数据分析。但是我们在迁移的过程中难免会碰到如何将传统数据库的功能也迁移到Hadoop的问题,比如说事务。事务作为传统数据库很重要的一个功能,在Hive中是如何实现的呢?Hive的实现有什么不一样的地方呢?我们将传统数据库的应用迁移到Hive如果有事务相关的场景我们该如何去转换并要注意什么问题呢?

本文会通过很多真实测试案例来比较Hive与传统数据库事务的区别,并在文末给出一些在Hive平台上使用事务相关的功能时的指导和建议。

ACID与实现原理


为了方便解释和说明后面的一些问题,这里重提传统数据库事务相关的概念,以下内容来源于网络。

Read more »

前言

本文主要介绍SparkSQL的优化器系统Catalyst,其设计思路基本都来自于传统型数据库,而且和大多数当前的大数据SQL处理引擎设计基本相同(Impala、Presto、Hive(Calcite)等)。

SQL优化器核心执行策略主要分为两个大的方向:

  1. 基于规则优化(RBO):是一种经验式、启发式地优化思路,更多地依靠前辈总结出来的优化规则,简单易行且能够覆盖到大部分优化逻辑,但是对于核心优化算子Join却显得有点力不从心。
  2. 基于代价优化 (CBO):根据代价估算确定一种代价最小的方案。

举个简单的例子,两个表执行Join到底应该使用BroadcastHashJoin还是SortMergeJoin?当前SparkSQL的方式是通过手工设定参数来确定,如果一个表的数据量小于这个值就使用BroadcastHashJoin,但是这种方案显得很不优雅,很不灵活。基于代价优化就是为了解决这类问题,它会针对每个Join评估当前两张表使用每种Join策略的代价,根据代价估算确定一种代价最小的方案。

Read more »

引言

一般来说,分布式数据集的容错性有两种方式: 数据检查点 和 记录数据的更新 。面向大规模数据分析,数据检查点操作成本很高,需要通过数据中心的网络连接在机器之间复制庞大的数据集,而网络带宽往往比内存带宽低得多,同时还需要消耗更多的存储资源。因此,Spark选择记录更新的方式。

但是,如果更新粒度太细太多,那么记录更新成本也不低。因此,RDD只支持粗粒度转换,即只记录单个块上执行的单个操作,然后将创建RDD的一系列变换序列(每个RDD都包含了他是如何由其他RDD变换过来的以及如何重建某一块数据的信息。因此RDD的容错机制又称“血统(Lineage)”容错)记录下来,以便恢复丢失的分区。

Lineage本质上很类似于数据库中的重做日志(Redo Log),只不过这个重做日志粒度很大,是对全局数据做同样的重做进而恢复数据。

Lineage机制

Lineage简介

相比其他系统的细颗粒度的内存数据更新级别的备份或者LOG机制,RDD的Lineage记录的是粗颗粒度的特定数据Transformation操作(如filter、map、join等)行为。当这个RDD的部分分区数据丢失时,它可以通过Lineage获取足够的信息来重新运算和恢复丢失的数据分区。因为这种粗颗粒的数据模型,限制了Spark的运用场合,所以Spark并不适用于所有高性能要求的场景,但同时相比细颗粒度的数据模型,也带来了性能的提升。

Read more »

列式存储

由于OLAP查询的特点,列式存储可以提升其查询性能,但是它是如何做到的呢?这就要从列式存储的原理说起,从图1中可以看到,相对于关系数据库中通常使用的行式存储,在使用列式存储时每一列的所有元素都是顺序存储的。由此特点可以给查询带来如下的优化:

1
2
3
查询的时候不需要扫描全部的数据,而只需要读取每次查询涉及的列,这样可以将I/O消耗降低N倍,另外可以保存每一列的统计信息(min、max、sum等),实现部分的谓词下推。
由于每一列的成员都是同构的,可以针对不同的数据类型使用更高效的数据压缩算法,进一步减小I/O。
由于每一列的成员的同构性,可以使用更加适合CPU pipeline的编码方式,减小CPU的缓存失效。

图1 行式存储VS列式存储
Read more »

先将总体的单位按某种特征分为若干次级总体(层),然后再从每一层内进行单纯随机抽样,组成一个样本的统计学计算方法叫做分层抽样。在spark.mllib中,用key来分层。

与存在于spark.mllib中的其它统计函数不同,分层采样方法sampleByKeysampleByKeyExact可以在key-value对的RDD上执行。在分层采样中,可以认为key是一个标签,
value是特定的属性。例如,key可以是男人或者女人或者文档id,它相应的value可能是一组年龄或者是文档中的词。sampleByKey方法通过掷硬币的方式决定是否采样一个观察数据,
因此它需要我们传递(pass over)数据并且提供期望的数据大小(size)。sampleByKeyExact比每层使用sampleByKey随机抽样需要更多的有意义的资源,但是它能使样本大小的准确性达到了99.99%

sampleByKeyExact()允许用户准确抽取f_k * n_k个样本,
这里f_k表示期望获取键为k的样本的比例,n_k表示键为k的键值对的数量。下面是一个使用的例子:

Read more »

前言

Dataset 是一种强类型的领域特定对象集合,可以在使用功能或关系操作的同时进行转换。每个 Dataset 也有一个名为 “DataFrame” 的无类型视图,它是 [[Row]] 的 Dataset。
Dataset 上可用的操作分为转换和动作:

转换:产生新的 Dataset ;包括 map, filter, select, and aggregate (groupBy).
动作:触发计算并返回结果 ;包括 count, show, or 写数据到文件系统。

Dataset是懒加载的,例如:只有提交动作的时候才会触发计算。在内部,Datasets表示一个逻辑计划,它描述生成数据所需的计算。当提交动作时,Spark的查询优化器会优化逻辑计划,并以并行和分布式的方式生成有效执行的物理计划。请使用explain 功能,探索逻辑计划和优化的物理计划。

为了有效地支持特定于领域的对象,需要[[Encoder]]。编码器将特定类型的“T”映射到Spark的内部类型系统。例如:给一个 Person 类,并带有两个属性:name (string) and age (int),编码器告诉Spark在运行时生成代码,序列化 Person 对象为二进制结构。

通常有两种创建Dataset的方法:

使用 SparkSession 上可用的 read 方法读取 Spark 指向的存储系统上的文件。
用现存的 Datasets 转换而来。

Dataset操作也可以是无类型的,通过多种领域专用语言(DSL)方法定义:这些操作非常类似于 R或Python语言中的 数据框架抽象中可用的操作。

Read more »

使用Java开发Spark程序,JavaRDD的功能算子中英文注释
JavaRDDLike的实现应该扩展这个虚拟抽象类,而不是直接继承这个特性。

JavaRDD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.apache.spark.api.java

private[spark] abstract class AbstractJavaRDDLike[T, This <: JavaRDDLike[T, This]]
extends JavaRDDLike[T, This]

/**
* Defines operations common to several Java RDD implementations.
*
* 定义几个Java RDD实现的常见操作。
*
* @note This trait is not intended to be implemented by user code.
*
* 该特性不打算由用户代码实现。
*/
trait JavaRDDLike[T, This <: JavaRDDLike[T, This]] extends Serializable {
def wrapRDD(rdd: RDD[T]): This

implicit val classTag: ClassTag[T]

def rdd: RDD[T]
Read more »

版本:spark2.1.1
目的:方便中文用户阅读源码,把时间花在理解而不是翻译上

初衷

开始立项进行翻译,一方面方便日后阅读源码,另一方面先粗粒度的熟悉下spark框架和组件。优化完之后希望能帮助更多的中文用户,节省翻译时间。

Read more »

parquet是一种列式存储。可以提供面向列的存储和查询。

Parquet的优势

在sparkSQL程序中使用parquet格式存储文件,在存储空间和查询性能方面都有很高的效率。

存储方面

因为是面向列的存储,同一列的类型相同,因而在存储的过程中可以使用更高效的压缩方案,可以节省大量的存储空间。

查询方面

在执行查询任务时,只会扫描需要的列,而不是全部,高度灵活性使查询变得非常高效。

Read more »