1.1 大数据及其带来的挑战
大数据具有数据量大(Volume)、数据类型多样(Variety)、产生与处理速度快(Velocity)、价值高(Value)的“4V”特性。
关系数据库解决了关系型数据的存储与OLTP(On-line Transaction Processing,在线事务处理)问题,以及之后出现的数据仓库解决了数据建模及OLAP(On-line analytical processing,在线分析处理)问题,但是在大数据环境下,传统的数据库和数据仓库都面临着可扩展性的问题。
1.2 大数据处理框架
基于分治、归并和函数式编程思想的MapReduce分布式计算框架。大数据处理框架拥有共同的编程模型,即MapReduce-like模型,采用“分治-聚合”策略来对数据进行分布并行处理。
1.3 大数据应用及编程模型
目前通用的大数据处理框架,如Hadoop、Dryad和Spark,都是以MapReduce编程模型为基础的。
MapReduce编程模型可以被简单地表示为:
- map阶段:
map <K1,V1> ⇒ list<K2,V2>
- reduce阶段:
reduce <K2,list(V2)> ⇒ list<K3,V3>
图1.1 WordCount应用的MapReduce执行流程
1.4 大数据处理框架的四层结构
一个大数据应用可以表示为<输入数据,用户代码,配置参数>。
大数据处理框架大体可以分为四层结构:用户层、分布式数据并行处理层、资源管理与任务调度层、物理执行层。
在用户层中,用户需要准备数据、开发用户代码、配置参数。之后,分布式数据并行处理层根据用户代码和配置参数,将用户代码转化成逻辑处理流程(数据单元及数据依赖关系),然后将逻辑处理流程转化为物理执行计划(执行阶段及执行任务)。资源管理与任务调度层根据用户提供的资源需求来分配资源容器,并将任务(task)调度到合适的资源容器上运行。物理执行层实际运行具体的数据处理任务。
图1.2 大数据处理框架的四层结构
1.4.1 用户层
输入数据
对于批式大数据处理框架,如Hadoop、Spark,用户在提交作业(job)之前,需要提前准备好输入数据。输入数据在应用提交后会由框架进行自动分块,每个分块一般对应一个具体执行任务(task)。
对于流式大数据处理框架,数据以微批(多条数据形成一个微批,称为mini-batch)或者连续(一条接一条,称为continuous)的形式进入流式大数据处理框架。
对于大数据应用,数据的高效读取常常成为影响系统整体性能的重要因素。为了提高应用读取数据的性能,学术界研究了如何通过降低磁盘I/O来提高性能。
用户代码
用户代码可以是用户手写的MapReduce代码,或者是基于其他大数据处理框架的具体应用处理流程的代码。在实际系统中,用户撰写用户代码后,大数据处理框架会生成一个Driver程序,将用户代码提交给集群运行。
图1.3 在Spark平台上Driver程序的运行模式
除了直接依赖底层操作手动撰写用户代码,用户还可以利用高层语言或者高层库来间接产生用户代码。比如Apache Pig、Spark之上的机器学习库MLlib,进行相关配置自动生成执行的任务。
配置参数
这些配置参数可以分为两大类:一类是与资源相关的配置参数,如buffer size定义框架缓冲区的大小;另一类是与数据流相关的配置参数,例如Hadoop和Spark中都可以设置partition个数。
由于Hadoop/Spark框架本身没有提供自动优化配置参数的功能,所以工业界和学术界研究了如何通过寻找最优配置参数来对应用进行性能调优。
1.4.2 分布式数据并行处理层
分布式数据并行处理层首先将用户提交的应用转化为较小的计算任务,然后通过调用底层的资源管理与任务调度层实现并行执行。
在Hadoop MapReduce中,这个转化过程是直接的。因为MapReduce具有固定的执行流程(map—Shuffle—reduce),可以直接将包含map/reduce函数的作业划分为map和reduce两个阶段。
与Hadoop MapReduce不同,Spark上应用的转化过程包含两层:逻辑处理流程、执行阶段与执行任务划分。
为了将用户代码转化为逻辑处理流程,Spark和Dryad对输入/输出、中间数据进行了更具体的抽象处理,将这些数据用一个统一的数据结构表示。在Spark中,输入/输出、中间数据被表示成RDD(Resilient Distributed Datasets,弹性分布式数据集)。
逻辑处理流程是一个有向无环图(Directed Acyclic Graph,简称DAG图)。如下图,其中的节点是数据单元RDD,每个数据单元里面的圆形是指RDD的多个数据分块,正方形专指输入数据分块。箭头是在RDD上的一些数据操作(也隐含了parent RDD和child RDD之间的依赖关系)。
图1.3 Spark应用转化与执行流程
为了将逻辑处理流程转化为物理执行计划,Spark首先根据RDD之间的数据依赖关系,将整个流程划分为多个小的执行阶段(stage)。之后,在每个执行阶段形成计算任务(task),计算任务的个数一般与RDD中分区的个数一致。与MapReduce不同的是,一个Spark job可以包含很多个执行阶段,而且每个执行阶段可以包含多种计算任务,因此并不能严格地区分每个执行阶段中的任务是map任务还是reduce任务。
1.4.3 资源管理与任务调度层
从系统架构上讲,大数据处理框架一般是主-从(Master-Worker)结构。主节点(Master节点)负责接收用户提交的应用,处理请求,管理应用运行的整个生命周期。从节点(Worker节点)负责执行具体的数据处理任务(task),并在运行过程中向主节点汇报任务的执行状态。
图1.4 Hadoop MapReduce框架的部署图,其中不同job的task可以分布在不同机器上
Spark支持不同的部署模式,如Standalone部署模式、YARN部署模式和Mesos部署模式等。其中Standalone部署模式与Hadoop MapReduce部署模式基本类似,唯一区别是Hadoop MapReduce部署模式为每个task启动一个JVM进程运行,而且是在task将要运行时启动JVM,而Spark是预先启动资源容器(Executor JVM),然后当需要执行task时,再在Executor JVM里启动task线程运行。
在运行大数据应用前,大数据处理框架还需要对用户提交的应用(job)及其计算任务(task)进行调度。任务调度的主要目的是通过设置不同的策略来决定应用或任务获得资源的先后顺序。典型的任务调度器包含先进先出(FIFO)调度器、公平(Fair)调度器等。
先进先出(FIFO)的任务调度器有两种类型的调度器:一类是应用调度器,决定多个应用(app)执行的先后顺序;另一类是任务调度器,决定多个任务(task)执行的先后顺序。
图1.5 先进先出(FIFO)的任务调度器
第二代Hadoop的资源管理与调度框架YARN能够同时为集群中运行的多种框架(如Hadoop MapReduce,Spark)提供资源管理等服务。UC Berkeley提出的Mesos与YARN类似,可以对集群上各种应用进行资源分配与任务调度,支持MapReduce作业、Spark作业、MPI作业等。,它们有一个共同的局限,即资源分配策略的执行依赖用户提供的资源需求与当前集群资源的监控信息,而不能根据应用的实际场景自动动态地调整资源分配。
1.4.4 物理执行层
大数据处理框架的物理执行层负责启动task,执行每个task的数据处理步骤。在物理执行时首先执行上游stage中的task,完成后执行下游stage中的task。
在Hadoop MapReduce中,每个task对应一个进程,也就是说每个task以JVM(Java虚拟机)的方式来运行,所以在Hadoop MapReduce中task的内存用量指的是JVM的堆内存用量。在Spark中,每个task对应JVM中的一个线程,而一个JVM可能同时运行了多个task,因此JVM的内存空间由task共享。
我们可以将task执行过程中主要消耗内存的数据分为以下3类:
- 框架执行时的中间数据。
- 框架缓存数据。
- 用户代码产生的中间计算结果。
由于大数据应用的内存消耗量很大,所以当前许多研究关注如何改进大数据处理框架的内存管理机制,以减少应用内存消耗。Spark社区采用堆外内存管理机制和基于堆外内存的Shuffle机制,提出了钨丝计划。另外,如何预测大数据应用的执行时间也被一些研究人员关注。
1.5 错误容忍机制
分布式文件系统在设计时一般都会考虑错误容忍机制,在实现时也会针对各种失效情况采取相应措施。
对于task的执行失败问题,框架的错误容忍机制比较简单,只是选择合适节点重新运行该task。对于某些可靠性问题引起的task执行失败,如内存溢出等,简单地重新运行task并不能解决问题,因为内存溢出的问题很有可能会重复出现。
据研究,在大数据应用错误分析方面,发现错误发生的主要原因是未定义的列、错误的数据模式、不正确的行格式等。发现故障主要是数组访问越界造成的,还有I/O异常。发现内存溢出的主要原因包括应用配置异常、数据流异常、代码空间复杂度过高和框架内存管理缺陷等。
1.6 其他大数据处理框架
Spark Structured Streaming和Apache Flink统一了批式处理与流式处理的执行流程。
1.7 扩展阅读
使用DataSet、DataFrame开发的应用可以更好地执行各种SQL操作,并利用Spark SQL引擎中的优化技术来对执行计划进行优化。
基于RDD应用的逻辑处理流程和物理执行计划与Spark SQL应用的Logical plan和Physical plan 有所不同:
- 基于RDD应用的逻辑处理流程指的是一系列RDD操作形成的输入/输出、中间数据及数据之间的依赖关系;物理执行计划指的是具体的执行阶段(stage)和执行任务(task)。park SQL应用中的Logical plan指的是将SQL脚本转化后的逻辑算子树,包含各种SQL操作。
- Physical plan指的是对逻辑算子树进行转化后形成的物理算子树,树中的节点可以转化为RDD及其操作,也可以直接生成实现Project()、filter()、join()等操作的Java代码。