• 大数据基础


    1. 背景

    在各行各业的发展中,无论来源、记录方式如何,人们必然会积累各种各样的数据,并且倾向于通过统计数据分析现实情况,以此作为指导行动方向的依据。因此,统计学中一直围绕着数据进行建模与问题分析,给出对数据背后反映问题的判断。

    由于计算机的发展,承载数据统计和分析的实体自然而然地变成了各式各样的计算机。在计算机和互联网的发展下,在数据分析领域也催生了一些新的计算形态。而且尽管各种行业的数据模型不同, 但是不同需求之间是有共性的。

    如今已经为人熟知的大数据的概念,包括规模的增长,异构多样的数据带来的各种处理需求,其实在计算机领域是可以预见到的。在小数据,单机的情况下可以良好工作的算法,在数据规模激增的情况下不一定行得通,需要以各种新的设计来解决相应的问题。

    在硬件上,表现为多核处理器和多机系统的发展;在软件层面,有对应高性能并行计算的MPI,当然也有以Google的MapReduce为滥觞的一系列集群式ETL的数据处理框架。

    Hadoop是大数据处理框架在开源社区的始祖,下文仅讨论Hadoop生态相关的计算框架。

    发展历程

    由于提升单台计算机的成本曲线让人望而生畏, 由相对廉价的计算机集群执行的分布式计算成为了一种现实的选择。

    因为互联网业务的特点,处理大量的文档,网络请求日志来生成报告乃至进行机器学习,大规模图学习成为其常见的场景。伴随着这些场景,Google的工程师实践并提出了MapReduce计算模型,同时贡献了GFS,Big Table。之后, 业界逐渐出现并演化了一批用于大数据处理的框架和组件,Hadoop即是其中的早期代表。

    Hadoop的组成至少包含以下部分:

    yarn是计算集群任务调度的服务中心;map reduce计算引擎;hdfs的文件系统。

    MapReduce本身的概念其实并不难理解,但是其面对真实场景需要解决大量的工程问题。

    以Hadoop为例,其本身就要处理很多异常情况。典型问题,如在集群中出现节点异常是家常便饭,每一步都可能出错或者被意外中断;mapreduce的数据分片经历了大量的基准测试和优化,在不同场景下要达到高性能的配置也相当复杂。hadoop的实现也没有达到一个完美的地步。hadoop只能处理批量离线数据,而且为了使用它执行一个操作经常需要做很多的MapReduce组合。由于其数据在处理过程中大部分都需要落盘,因此hadoop在性能上并没有优势,直接使用map reduce的方式到今天为止已经完全淡出工业界了。

    尽管如此,入门大数据领域的时候了解MapReduce仍然是有其意义的。

    2. MapReduce计算模型

    我们了解一下MapReduce的计算模型。

    MapReduce是一个在多个节点的集群中处理数据的计算框架/过程。一个MapReduce的系统通常由map、shuffle和reduce组成。数据的流向是从master节点发送数据开始, 到reduce节点结束。

    一个典型的map reduce包含下图几个阶段:

    map,reduce的计算形式:

    map (k1, v1) -> list(k2, v2)

    reduce (k2, list(v2)) -> list(v2)

    map阶段之前,数据会形成分片,由master节点派发给不同的worker节点;每个数据的分片中可能包含了不同的key;

    map阶段,每个worker节点执行map计算任务;

    map阶段是并行的,在worker节点计算输出后保存(本地),传给下一个阶段;

    从map到reduce,数据会经历shuffle,其过程取决于具体的实现,并不是统一的;

    reduce阶段也是在worker节点完成。worker接收到master节点分配的reduce任务,拉取map阶段的输出作为输入,计算最终的输出。跟Map阶段不同,Reduce阶段不能并行。

    如何容错

    master节点记录了每个节点的任务状态,并且通过ping来判断worker节点是否失败; master节点在worker任务失败的时候会重置worker节点的状态;整个任务的执行依赖于worker对任务处理的原子性。

    combiner函数

    MapReduce同时包含了combiner函数,也是针对map的输出进行处理,跟reducer的区别是,它是处理worker本地数据的,其输出将作为reducer的输入;针对本来要发送给reducer的数据,做一些局部的排序或合并。而有序的数据在处理上可以取出小块切片后reduce而不影响结果,既能减少网络IO,也能减少reduce阶段的计算量。

    shuffle阶段

    shuffle包含map阶段和reduce阶段的操作,是一个统称;

    在map阶段,根据key,val将数据划分到指定的reduce任务,这个叫做partitioner,也是shuffle的一个阶段;

    在reduce阶段,shuffle根据map输出的结果,对内存和磁盘内的数据处理,对将由同一个reducer处理的数据进行合并。

    需要注意的是,reduce阶段的shuffle排序和合并的算法在使用Spark框架的时候无法定制,仅能通过comparator指定如何排序。

    combiner优化

    当reduce满足结合律,可以使用reducer直接替换combiner

    如果reduce不满足结合律,无法直接用reducer替换combiner,具体问题具体分析

    2.1 MapReduce combiner的实际计算样例

    计算平均值:

      combiner是优化中间计算的一种方式,当使用combiner时,需要注意reducer是否满足结合率;

    不妨设两个节点上有待执行map的数据集合,为A1,A2,显然,列数据的平均值不能用各自平均值取平均: AVG(AVG(A1), AVG(A2)) != AVG(A1∪A2)

    这种情况需要在每条数据附加一个记录数1,最后在reduce阶段以总数和记录总数求得平均值;

    计算中位数

    另一个例子是计算数据的中位数: 这个目标任务的combiner函数不能是简单的取中位数。

    一种方案是将map 输出的v2存为列表,这种方法会占用较多的内存;

    在第一种方案的基础上其实可以进行优化:不保留所有的v2,而是记录v2的取值和对应的计数,最后得到的就是类似<k1, v1, count1>, <k2, v2, count2> ...的输出,其中列表是排好序的,在reduce阶段,遍历key的列表,在count1+count2...超过一半的总数时得到对应的中位数;同样可以优化内存的使用。

    2.2. Spark计算框架

    Spark是一个最为流行的大数据计算引擎。Spark基于hadoop的mapreduce计算模型做出抽象,并且在原有的资源调度、迭代计算的基础上做了许多优化,同时保留了对hadoop的hdfs,yarn等依赖。尽管它跟hadoop有关联,但是其跟hadoop并不是互为替换的关系。除此之外,伴随着更加方便的API和程序框架诞生的其他计算组件,则构建了Spark大数据处理的生态。

    2.3 Hadoop Shuffle和Spark Shuffle

    从功能上看,Hadoop和Spark的Shuffle是类似的,没有区别。从实现的细节上,两者才有不同。map端的shuffle一般为shuffle的Write阶段,reduce端的shuffle一般为shuffle的read阶段。

    相对于Hadoop的 MapReduce,最开始的Spark在默认的情况下不对 Shuffle 的数据进行排序,即Hash Shuffle,目的是为了减少shuffle时候的性能浪费,对不需要排序的数据忽略这一步。但是,后来Spark的Shuffle经历了Hash、Sort、Tungsten-Sort(堆外内存)三阶段发展历程。

    对于Hash Shuffle来说,在 Map Task 过程按照 Hash 的方式重组 Partition 的数据,不进行排序。每个 Map Task 为每个 Reduce Task 生成一个文件,通常会产生大量的文件(即对应为 M*R 个中间文件),伴随大量的随机磁盘 I/O 操作与大量的内存开销。

    在Spark 1.2以后的版本中,默认的ShuffleManager改成了SortShuffleManager。SortShuffleManager相较于HashShuffleManager来说,有了一定的改进。主要就在于,每个Task在进行shuffle操作时,虽然也会产生较多的临时磁盘文件,但是最后会将所有的临时文件合并(merge)成一个磁盘文件,因此每个Task就只有一个磁盘文件。在下一个stage的shuffle read task拉取自己的数据时,只要根据索引读取每个磁盘文件中的部分数据即可[4]。而且针对不同的算子,会判断是否启用SortShuffle,从而避免不必要的排序。

     

    2.4 Spark SQL, Spark Streaming, Structured Streaming

    在Spark中,会用到RDD,DataFrame,DataSet(类似DataFrame)几种核心数据结构。

    RDD为resilient distributed dataset,弹性分布式数据集,其结构上是Java 或Scala对象的集合.。Spark中在其上定义了很多操作,并且其接口类似函数式编程,能够简洁直观地表示一系列操作。其缺点是性能难以优化,而且会带来使用的时候本质上要自己维护DAG的困难。

    DataFrame是数据的一个不可变分布式集合,其结构是列式存储,区别于RDD, 可以通过其列名直接访问数据列;相较RDD,DataFrame 是高级的 API,提供类似于SQL 的 query 接口。

    Spark Steaming的出现早于Structured Streaming,处理的对象是DStream, 而Structured Streaming是Spark 2.0发布带来的特性,处理的对象是DataFrame。

    两者都是以时间划分出微批处理,针对一定时间间隔的小批数据进行处理,以此模拟流式数据处理。

    其中,Spark Steaming接近RDD对象数据结构,缺点是效率不高。而Structured Streaming同样是微批处理的形式,但其在DataFrame基础上的流式处理性能提升了。

    简单来说,跟Hadoop相比,Spark具有如下的优点:

    基于DAG的任务执行调度机制,算子的更强表现力,降低了开发的心智负担,更加贴近实际的开发;更加高效的计算执行模式,让更多的数据计算直接在内存中执行减少IO开销。

    3. 设计模式、算子与流式计算

    MapReduce设计模式

    从MapReduce开始,其实就已经有了很多设计模式,可以参见《MapReduce设计模式》。

    一些典型的设计模式如下:

    数值概要设计模式 numerical summarization pattern,计算总数,最大值,最小值等都是概要模式

    索引模式 indexing pattern 产生一个数据集的索引以达到快速检索的目的,例如文本的倒排索引

    过滤模式 filtering pattern 过滤掉一些不需要的数据。

    Spark的算子或多或少是这些map reduce设计模式的体现。

    算子的分类

    (1)Transformation变换/转换算子:这种变换不会执行真正的作业,因为一些变换不需要马上得到结果,而且可以在多个变换后计算复合操作,减少计算量。

    (2)Action行动算子:这类算子会触发提交job作业,并将数据输出到Spark系统。

    Transformation变换/转换算子

    1. map算子

    2. flatMap算子

    3. mapPartitions算子

    4. mapPartitionsWithIndex算子

    5. cache算子、persist算子

    6. union算子

    7. cartesian算子

    8. groupBy算子

    9. filter算子

    10. sample算子

    11. combineByKey 算子 reduceByKey算子

    12. join算子

    Action类型的算子:

    1.foreach

    2.saveAsTextFile

    3.collect

    4.count

    4. Hadoop生态的组件

    Pig 和Hive

    Pig和HiveQL是在HDFS上使用的数据查询语言。

    HBase, Cassandra, HDFS

    HBase是仿照谷歌BitTable的开源实现,是面向列的开源数据库;HDFS是GFS的开源实现,是一种文件系统;Cassandra是个分布式的key-value数据库。

    Pregel,GraphX

    图数据结构是分布式计算中一个重要的领域。图的数据可以分为网络、树、类RDBMS结构、稀疏矩阵以及其它一些结构(from Spark GraphX in Action)。为了处理图,在OLTP领域有Neo4j, NebulaGraph等组件;而在OLAP领域以Pregel,GraphX等为代表。

    Pregel是一个迭代式的分布式图计算算法和系统,在此基础上有Spark的GraphX。到目前为止,GraphX还有一些尚未实现的特性和优化空间。

    数据转换Sqoop

    sqoop 是一个数据库转换的工具,提供了从hadoop文件格式到关系型数据库之间的数据互转。

    Storm,Flink

    前面讲到Spark可以进行流式数据的处理,然而Spark到目前为止的流式处理延迟只能达到秒级,而另外两种流式处理框架Storm、Flink可以达到μs到ms级。

    这里只讲Flink。为什么Spark跟Flink会有如此大的差异,主要还是数据处理原理的差异。Spark的处理方式是将流式处理看作批处理的一种特殊形式,每收到一个间隔的数据才进行处理,在实时性上难以提升。

    而Flink处理的模型是基于算子(operator)的连续数据流。Flink设计了一套高度灵活的窗口机制,从而对数据能够执行真正的流式计算,每有一条数据就能进行期望的算子操作。

    上图中是一个Dataflow,数据src,数据sink,以及transformation算子均为节点,它们通过stream相连.数据从一个operator出发,经过stream被其他operator处理。同时,一个 stream 可以包含多个分区,一个算子可以被分成多个算子的子任务,每一个子任务是在不同的线程或者不同的机器节点中独立执行的。

    Flink也提供了跟Spark一样的DataSet,DataStream API,下图是Flink的架构。

    5. 计算样例

    PageRank如何使用MapReduce计算

    PageRank是搜索引擎中一个计算网页重要性的算法。可以使用Map Reduce实现简化的PageRank。在一个图中,网页之间通过超链接相连,因此可以用一个有向图/邻接矩阵表示。

    PageRank的数据结构:

    矩阵F(A,B),项F(x,y)表示从A到B的出链关系,1为有出链

    算法:

    初始化的时候每个网页是一个相同的均值,每次的网页i的值为刚好其他网页权重按比例分配给它的权重之和。

    而对网页i来说,它分配给其他网页的权重是其已有权重的平均值。即W(u) = Σ D(v属于Su)/Out(v)。

    Map的时候,针对网页u,计算网页u到其他网页的权重,每条记录<u,W(u)>变成列表<vi,W(u)/count(vi∈Su)> (i = 1,2,...)

    Reduce的时候,由vi为key,加和所有的权重,即得到网页v的权重。(v跟u不是同一个网页)

    一次计算得到的权重不是最终结果,PageRank要经过多次迭代计算得到最终各个网页的权重[7]。

    这是一个马尔科夫随机过程。为了避免该过程不收敛,可以加入虚拟的节点,以及一个概率点击系数,表示从任意节点可能跳转到该节点的概率。

    References

    [1] Dean J ,  Ghemawat S . MapReduce: Simplified Data Processing on Large Clusters[C]// Proceedings of the 6th conference on Symposium on Opearting Systems Design & Implementation - Volume 6. USENIX Association, 2004.

    [2] MapReduce-MPI Library, https://mapreduce.sandia.gov/

    [3] Hadoop Map/Reduce教程, http://hadoop.apache.org/docs/r1.0.4/cn/mapred_tutorial.html

    [4] MapReduce Shuffle 和 Spark Shuffle, https://cloud.tencent.com/developer/article/1651735, 2020

    [5] Carbone P , Katsifodimos A , † Kth, et al. Apache flink : Stream and batch processing in a single engine.  2015.

    [6] Data Streaming Fault Tolerance, https://ci.apache.org/projects/flink/flink-docs-release-1.3/internals/stream_checkpointing.html#checkpointing

    [7] PageRank in Map Reduce, https://medium.com/swlh/pagerank-on-mapreduce-55bcb76d1c99

  • 相关阅读:
    fastclick.js插件使用
    iphone X 的适配
    常用js方法整理
    gulp(1) 的使用
    C# Datatable 添加列
    Microsoft visual studio已停止工作最全解决办法
    微服务
    获取指定页的记录
    谷歌浏览器安装ie_tab()报错The 'manifest_version' key must be present and set to 2 (without quotes)的解决办法
    Javascript常用代码汇总
  • 原文地址:https://www.cnblogs.com/wangzming/p/14674643.html
Copyright © 2020-2023  润新知