文件系统是操作系统在硬盘或者分区上保存文件信息的方法和数据结构。
分布式文件系统是一种通过网络实现文件在多台主机上进行分布式存储的文件系统。
文件系统是操作系统在硬盘或者分区上保存文件信息的方法和数据结构。文件系统用于管理机器上的文件和目录,使之能够被有效地存取。
在操作系统中,每个文件和目录都被指定了一个文件名,用户按文件名存取文件,而实际上,文件和目录在磁盘中是按照柱面、磁道等物理位置存放的,文件系统能够将操作系统对文件的按名存取转化成按磁盘的物理位置进行读写。
文件储存在硬盘上,硬盘的最小存储单位叫做扇区(Sector)。每个扇区储存512字节
(相当于0.5KB)。
操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取
多个扇区,即一次性读取一个块(block)。这种由多个扇区组成的块,是文件存取的最小单位。
块的大小,最常见的是4KB,即连续八个扇区组成一个 block。
文件数据都储存在块中,还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译为索引节点。
分布式文件系统(Distributed File System,DFS)是一种通过网络实现文件在多台主机上进行分布式存储的文件系统。分布式文件系统一般采用“客户机/服务器”(client/server)模式,客户端以特定的通信协议通过网络与服务器建立连接,提出文件访问请求,客户端和服务器可以通过设置访问权限限制请求对方底层存储块的访问。
分布式文件系统的设计目标包括通透性,并发控制,可伸缩性,容错以及安全。
分布式文件系统在物理结构上是由计算机集群中的多个节点构成的,这些节点分为两类,一
类叫主节点(Master Node)或者也被称为名称结点(NameNode),另一类叫从节点(Slave Node)或者也被称为数据节点(DataNode)。
名称节点负责文件和目录的创建、删除和重命名等,同时管理着数据节点和文件块的映射关系,因此客户端只有访问名称节点请求文件块所在的位置,进而到相应位置读取所需文件块。
数据节点负责数据的存储和读取,在存储时,由名称节点分配存储位置,然后由客户端把数据直接写入相应数据节点;在读取时,客户端从名称节点获取数据节点和文件块的映射关系,然后就可以到相应位置访问文件块,数据节点也要根据民称个节点的命令创建、删除和复制数据块。
HDFS默认一个块64MB,一个文件被分成多个块,以块作为存储单位
在传统的文件系统中,为了提高磁盘读写效率,一般以数据块为单位,而不是以字节为单位。
块的大小远远大于普通文件系统,可以最小化寻址开销(包括磁盘寻道开销、数据块的定位开销)
HDFS采用抽象的块概念可以带来以下几个明显的好处:
在HDFS中,名称节点(NameNode)负责文件和目录的创建、删除和重命名等,同时管理着数据节点和文件块的映射关系。名称节点保存了两个核心的数据结构,即fsimage和edits。
fsimage
用于维护文件系统树以及文件树中所有的文件和目录的元数据。edits
中记录了所有针对文件的创建、删除、重命名等操作。每个fsimage文件存储的都是文件系统元数据信息(文件及目录结构,组成文件的块的信息,副本数量信息),如果namenode发生故障,最近的fsimage文件会被载入到内存中,用来重构元数据的最近状态,再从相关点开始向前执行edits日志文件中记录的每个事务。
fsimage文件没有记录文件包含哪些块以及每个块存储在哪个数据节点。而是由名称节点把这些映射信息保留在内存中,当数据节点加入HDFS集群时,数据节点会把自己所包含的块列表告知给名称节点,此后会定期执行这种告知操作,以确保名称节点的块映射是最新的。
在名称节点启动的时候,它会将fsimage
文件中的内容加载到内存中,之后再执行edits
文件中的各项操作,使得内存中的元数据保持最新。
一旦在内存中成功建立文件系统元数据的映射,则创建一个新的fsimage文件和一个空的edits文件
名称节点启动成功进入正常状态之后,HDFS中的更新操作会写到edits文件中,因为fsimage文件一般都很大(GB级别的很常见),如果所有的更新操作都往fsimage文件中添加,这样会导致系统运行的十分缓慢,往edits文件里面写就不会这样,因为edits要小很多。
名称节点在启动的过程中出于“安全模式”,只能对外提供读操作,无法提供写操作。启动过程结束后,系统就会退出安全模式,进入正常与逆行状态,对外继续提供读写操作。
在名称节点运行期间,HDFS的所有更新操作都是直接写到edits中,久而久之, edits文件将会变得很大。
虽然这对名称节点运行时候是没有什么明显影响的,但是,当名称节点重启的时候,名称节点需要先将fsimage里面的所有内容映像到内存中,然后再一条一条地执行edits中的记录,当edits文件非常大的时候,会导致名称节点启动操作非常慢,而在这段时间内HDFS系统处于安全模式,一直无法对外提供写操作,影响用户的使用。
如何解决?答案是:SecondaryNameNode第二名称节点
第二名称节点是HDFS架构中的一个组成部分,它是用来保存名称节点中对HDFS元数据信息的备份,并减少名称节点重启的时间。
SecondaryNameNode一般是单独运行在一台机器上。
它可以完成edits和fsimage的合并操作,减小editlog文件大小,缩短名称节点重启的时间
作为名称节点的检查点,保存名称节点的元数据信息
数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者是名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块的列表。
每个数据节点中的数据会被保存在各自节点的本地Linux文件系统中
客户端是用户操作HDFS最常用的方式,HDFS在部署时都提供了客户端
HDFS客户端是一个库,暴露了HDFS文件系统接口,这些接口隐藏了HDFS实现中的大部分复杂性
严格来说,客户端并不算是HDFS的一部分
客户端可以支持打开、读取、写入等常见的操作,并且提供了类似Shell的命令行方式来访问HDFS中的数据
此外,HDFS也提供了Java API,作为应用程序访问文件系统的客户端编程接口
HDFS只设置唯一一个名称节点,这样做虽然大大简化了系统设计,但也带来了一些明显的局限性,具体如下:
(1)命名空间的限制:名称节点是保存在内存中的,因此,名称节点能够容纳的对象(文件、块)的个数会受到内存空间大小的限制。
(2)性能的瓶颈:整个分布式文件系统的吞吐量,受限于单个名称节点的吞吐量。
(3)隔离问题:由于集群中只有一个名称节点,只有一个命名空间,因此,无法对不同应用程序进行隔离。
(4)集群的可用性:一旦这个唯一的名称节点发生故障,会导致整个集群变得不可用。
不同的map任务之间不会进行通信,不同的reduce任务之间也不会发生任何信息交换。
HDFS 以固定大小的block为基本单位存储数据,而对于MapReduce而言,其处理单位是 split。
split 是一个逻辑概念,它只包含一些元数据信息,比如数据起始位置、数据长度、 数据所在节点等。它的划分方法完全由用户自己决定。
(1)MapReduce框架使用InputFormat模块做Map前的预处理,比如验证输入的格式是否符合输入定义;然后,将输入文件切分为逻辑上的多个InputSplit,InputSplit是MapReduce对文件进行处理和运算的输入单位,只是一个逻辑概念,每个InputSplit并没有对文件进行实际切割,只是记录了要处理的数据的位置和长度。
(2)因为InputSplit是逻辑切分而非物理切分,所以还需通过RecordReader根据InputSplit中的信息来处理InputSplit中的具体记录,加载数据并转换为适合Map任务读取的键值对,输入给Map任务。
(3)Map任务会根据用户自定义的映射规则,输出一系列的
(4)为了让Reduce可以并行处理Map的结果,需要对Map的输出进行一定的分区(partition)、排序(sort)、合并(combine)、归并(merge)等操作,得到
(5)Reduce以一系列
(6)OutpFormat模块会验证输出目录是否已经存在以及输出结果类型是否符合配置文件中的配置类型,如果都满足,就输出Reduce的结果到分布式文件系统。
shuffle是指对Map任务输出结果进行分区、排序、合并、归并等处理并交给Reduce的过程。
合并(Combine)和归并(Merge)的区别:
两个键值对<“a”,1>和<“a”,1>,如果合并,会得到<“a”,2>,如果归并,会得到<“a”,<1,1>>
Apache Hadoop YARN (Yet Another Resource Negotiator,另一种资源协调者) 是一种新的Hadoop 资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一管理和数据共享等方面带来了巨大好处。
Yarn主要由ResourceManager、NodeManager、ApplicationMaster和Container等几个组件构成。
ResourceManager主要负责整个系统的资源管理和分配,内部主要有两个组件:
ApplicationMaster是应用程序级别的,每个ApplicationMaster 管理运行在YARN上的应用程序。 YARN 将ApplicationMaster看做是第三方组件,ApplicationMaster负责和ResourceManager scheduler 协商资源,并且和NodeManager通信来运行相应的task。ResourceManager 为 ApplicationMaster 分配Container,这些Container将会用来运行task。
ApplicationMaster也会追踪应用程序的状态,监控Container的运行进度。
当Container运行完成,ApplicationMaster 将会向ResourceManager注销这个Container;
如果是整个作业运行完成,其也会向ResourceManager注销自己,这样这些资源就可以分配给其他的应用程序使用了。
NodeManager是YARN中每个节点上的代理,它管理Hadoop集群中单个计算节点,根据相关的设置来启动Container。NodeManager会定期向ResourceManager发送心跳信息来更新其健康状态。同时其也会监督Container的生命周期管理,监控每个Container的资源使用(内存、 CPU等)情况,追踪节点健康状况,管理日志和不同应用程序用到的附属服务(auxiliary service)。
总体来说, NodeManager有以下作用
Container是与特定节点绑定的,其包含了内存、CPU磁盘等逻辑资源。容器是由ResourceManager scheduler服务动态分配的资源构成。容器授予 ApplicationMaster使用特定主机的特定数量资源的权限。ApplicationMaster也是在容器中运行的,其在应用程序分配的第一个容器中运行。
在启动MapReduce之前,确保待处理的文件放在HDFS上面。
MapReduce应用将请求提交给RM,由RM创建对应的Job,一个应用对应一个Job。
Job提交前,先将待处理的文件进行分片(Split)。MR框架默认将一个块(Block)作为一个分片。客户端应用可以重定义块与分片的映射关系。
Job提交给RM,RM根据NM的负载在NM集群中挑选合适的节点调度AM, AM负责Job任务的初始化并向RM申请资源,由RM调度合适的NM启动Container, Container来执行Task。
Map的输出放入一个环形内存缓冲区,当缓冲区数据溢出时,需将缓冲区中的数据写入到本地磁盘,写入本地磁盘之前通常需要做如下处理:
(’Hi’,’1’),(‘Hello’,’1’)
重新排序为(‘Hello’,’1’), (’Hi’,’1’)
。(’Hi’,’1’), (’Hi’,’1’),(‘Hello’,’1’), (Hello’,’1’)
进行合并操作为(’Hi’,’2’), (‘Hello’,’2’)
。通常在Map Task任务完成MOF输出进度到**3%**时启动Reduce,从各 个Map Task获取MOF文件。前面提到Reduce Task个数由客户端决 定,Reduce Task个数决定MOF文件分区数。因此Map Task输出的 MOF文件都能找到相对应的Redcue Task来处理。
前面提到的MOF文件是经过排序处理的。当Reduce Task接收的数据量不大时,则直接存放在内存缓冲区中,随着缓冲区文件的增多, MR后台线程将它们合并成一个更大的有序文件,这个动作是Reduce阶段的Merge操作,过程中会产生许多中间文件,最后一次合并的结果直接输出到用户自定义的Reduce函数。
步骤 1:用户编写客户端应用程序,向 YARN提交应用程序,提交的内容包括ApplicationMaster 程序、启动 ApplicationMaster 的命令、用户程序等。
步骤 2:YARN 中的 ResourceManager 负责接收和处理来自客户端的请求。接到客户端应用程序请求后,ResourceManager里面的调度器会为应用程序分配一个容器。同时,ResourceManager 的应用程序管理器会与该容器所在的 NodeManager 通信,为该应用程序在该容器中启动一个ApplicationMaster。
步骤 3:ApplicationMaster 被创建后会首先向 ResourceManager 注册,从而使得用户可以通过 ResourceManager 来直接查看应用程序的运行状态。接下来的步骤4~7 是具体的应用程序执行步骤。
步骤 4:ApplicationMaster 采用轮询的方式通过 RPC 协议(Remote Procedure Call )向 ResourceManager 申请资源。
步骤 5:ResourceManager 以“**容器”**的形式向提出申请的 ApplicationMaster 分配资源,一旦 ApplicationMaster 申请到资源后,就会与该容器所在的NodeManager 进行通信,要求它启动任务。
步骤 6:当 ApplicationMaster 要求容器启动任务时,它会为任务设置好运行环境(包括环境变量、JAR 包、二进制程序等),然后将任务启动命令写到一个脚本中,最后通过在容器中运行该脚本来启动任务。
步骤 7:各个任务通过某个RPC 协议向ApplicationMaster 汇报自己的状态和进度,让 ApplicationMaster 可以随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务。
步骤 8:应用程序运行完成后,ApplicationMaster 向 ResourceManager 的应用程序管理器注销并关闭自己。若 ApplicationMaster 因故失败,ResourceManager中的应用程序管理器会监测到失败的情形,然后将其重新启动,直到所有的任务执行完毕。
除char类型以外,每个Java基本类型的Writable封装,其类的内部都包含一个对应基本类型的成员变量value,get()
和set()
方法就是用来对该变量进行取值/赋值操作的。这些类型都位于org.apache.hadoop.io
包中
序列化是Hadoop核心的一部分,在Hadoop中,位于org.apache.hadoop.io
包中的Writable
接口是Hadoop序列化格式的实现。
Hadoop Writable接口是基于DataInput和DataOutput实现的序列化协议,紧凑(高效使用存储空间),快速(读写数据、序列化与反序列化的开销小)。Hadoop中的键(key)和值(value)必须是实现了Writable接口的对象(键还必须实现WritableComparable,以便进行排序)。
package org.apache.hadoop.io;
import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;
public interface Writable {
/*
object将自身字段序列化后的字节流写入输出流out中。
参数:
out - 接收object序列化后的字节流的输出流.
*/
void write(DataOutput out) throws IOException;
/*
将输入流in中的字节流反序列化然后写入object的字段
参数:
字节流的出处
*/
void readFields(DataInput in) throws IOException;
}
WritableComparable接口定义如下:
package org.apache.hadoop.io;
public interface WritableComparable<T> extends Writable, comparable<T> {
}
WritableComparable没有方法,其方法都是通过继承而来,继承自Writable接口的有以下两个方法。
void write(DataOutput out) throws IOException;
void readFields(DataInput in) throws IOException;
还有继承自comparable的方法,comparable是属于java.lang.*中的一个接口,它只有一个方法。
int compareTo( T other);
/*
比较此对象与指定对象other的顺序。如果该对象小于、等于或大于指定对象,则
分别返回负整数、零或正整数。
参数:other - 要比较的对象。
返回:负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。
*/
WritableComparable
或者Writable
get
/set
函数write
方法并添加逻辑以写入所有字段值(就是调用基本类型的write方法)readFields
方法从输入流读取所有字段值compareTo
方法并实现自定义数据类型排序的逻辑Hadoop中自带了一个默认的分区类HashPartitioner
,继承Partitioner
类,提供了一个getPartition
的方法,定义如下:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
public int getPartition(K key, V value, int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
实现了将key均匀分布在Reduce Tasks上,例如:如果Key为Text的话,Text的hashcode方法跟String的基本一致,得到一个int整数。但是,如果string太大的话这个int整数值可能会溢出变成负数,所以和整数的上限值Integer.MAX_VALUE(即0111111111111111)进行与运算,然后再对reduce任务个数取余,这样就可以让key均匀分布在reduce上。
分区的作用:
HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,是谷歌BigTable的开源实现,主要用来存储非结构化和半结构化的松散数据。
(1)数据类型:关系数据库采用关系模型,具有丰富的数据类型和存储方式,HBase则采用了更加简单的数据模型,它把数据存储为未经解释的字符串。用户可以把不同格式的结构化数据和非结构化数据都序列化成字符串保存到HBase中。
(2)数据操作:关系数据库中包含了丰富的操作,其中会涉及复杂的多表连接,通常借助于多个表之间的主外键关联实现。HBase操作则不存在复杂的表与表之间的关系,只有简单的插入、查询、删除、清空等,因为HBase在设计上就避免了复杂的表和表之间的关系,通常只采用单表的主键查询。
(3)存储模式:关系数据库是基于行模式存储的。HBase是基于列存储的,每个列族都由几个文件保存,不同列族的文件是分离的。
(4)数据索引:关系数据库通常可以针对不同列构建复杂的多个索引,以提高数据访问性能。HBase只有一个索引——行键,通过巧妙的设计,HBase中的所有访问方法,或者通过行键访问,或者通过行键扫描,从而使得整个系统不会慢下来。
(5)数据维护:在关系数据库中,更新操作会用最新的当前值去替换记录中原来的旧值, 旧值被覆盖后就不会存在。而在HBase中执行更新操作时,并不会删除数据旧的版本,而 是生成一个新的版本,旧有的版本仍然保留。
(6)可伸缩性:关系数据库很难实现横向扩展,纵向扩展的空间也比较有限。相反, HBase和BigTable这些分布式数据库就是为了实现灵活的水平扩展而开发的,能够轻易地通过在集群中增加或者减少硬件数量来实现性能的伸缩。
HBase中需要根据行键、列族、列限定符和时间戳来确定一个单元格,因此,可以视为一个“四维坐标”,即[行键, 列族, 列限定符, 时间戳]
将一个数据表按Key值范围连续划分为多个的子表,这个子表,在HBase中被称作 “Region”。
每一个Region都关联一个Key值范围,即一个使用StartKey和EndKey描述的区间。
事实上,每一个Region仅仅记录StartKey就可以了,因为它的EndKey就是下一个 Region的StartKey。
Region是HBase分布式存储的最基本单元。
RegionServer是HBase的数据服务进程。 负责处理用户数据的读写请求。
Region由RegionServer管理。所有用户数据的读写请求,都是和RegionServer上的Region进行交互。
Region可以在RegionServer之间迁移。
每个RegionServer负责管理一个region集合。
ColumnFamily是Region的一个物理存储单元。同一个Region下面的多个ColumnFamily, 位于不同的路径下面。
一个表在水平方向上由一个或多个Column Family组成。一个Column Family可以由任意多个Column组成。Column是CF下的一个标签,可以在写入数据时任意添加,因此CF支持动态扩展,无需预先定义Column的数量和类型。HBase中表的列非常稀疏,不同行的列的个数和类型都可以不同。
Hive是基于Hadoop构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop分布式文件系统中的数据:
Hive SQL
,使不熟悉MapReduce的用户可以很方便地利用SQL语言查询、汇总和分析数据。mapper
和reducer
作为插件来支持Hive做更复杂的数据分析。数据仓库(DataWarehouse,DW)
数据仓库是一个面向主题的(SubjectOriented)、集成的(Integrated)、相对稳定的(Non-Volatile)、反映历史变化(TimeVariant)的数据集合,用于支持管理决策。
可以对多种业务数据进行筛选和整合,用于数据分析、数据挖掘、数据报表。
查询语言 | HiveQL | SQL |
---|---|---|
数据存储位置 | HDFS | 本地FS |
数据格式 | 用户定义 | 系统决定 |
数据更新 | 不支持 | 支持 |
索引 | 新版本有,但弱,仅支持有限索引 | 有,支持复杂索引 |
执行 | MapReduce、Tez、Spark | Executor |
执行延迟 | 高 | 低 |
可扩展性 | 高 | 低 |
数据规模 | 大 | 小 |
hive数据分成两类:数据文件和元数据。
Driver负责将hive sql
解析和优化HQL
语句,将其转换成一个Hive Job(可以是MapReduce,也可以是Spark等其他任务)并提交给Hadoop集群。
① 用户通过用户接口连接Hive,发布Hive SQL
② Hive解析查询并制定查询计划
③ Hive将查询转换成MapReduce作业
④ Hive在Hadoop上执行MapReduce作业
内部表与关系数据库中的Table在概念上类似。每一个Table在Hive中都有一个相应的目录存储数据。所有的Table数据(不包括External Table)都保存在这个目录中。删除表时,元数据与数据都会被删除。
外部表指向已经在HDFS中存在的数据。
它和内部表在元数据的组织上是相同的,而实际数据的存储则有较大的差异。
内部表的创建过程和数据加载过程这两个过程可以分别独立完成,也可以在同一个语句中完成,在加载数据的过程中,实际数据会被移动到数据仓库目录中;之后对数据访问将会直接在数据仓库目录中完成。删除表时,表中的数据和元数据将会被同时删除。
而外部表只有一个过程,加载数据和创建表同时完成,实际数据是存储在LOCATION后面指定的 HDFS 路径中,并不会移动到数据仓库目录中。当删除一个External Table时,仅删除该链接
如何选择使用内部表或外部表?
Partition
就是一种对表进行粗略划分的机制,可以实现加快查询速度的组织形式。
在Hive中,表中的一个Partition对应于表下的一个目录,所有的Partition的数据都存储在对应的目录中。
Buckets
是将表的列通过Hash算法进一步分解成不同的文件存储。
它对指定列计算Hash,根据Hash值切分数据,目的是为了并行,每一个Bucket对应一个文件。
分区是粗粒度的划分,桶是细粒度的划分,这样做为了可以让查询发生在小范围的数据上以提高效率。适合进行表连接查询、适合用于采样分析。
Spark的生态系统主要包含了Spark Core、Spark SQL、Spark Streaming、MLlib和GraphX等组件。
应用场景 | 时间跨度 | 其它框架 | Spark生态系统中的组件 |
---|---|---|---|
复杂的批量数据处理 | 小时级 | MapReduce | Spark |
基于历史数据的交互式查询 | 分钟级、秒级 | Hive、Impala、Dremel、Drill | Spark SQL |
基于实时数据流的数据处理 | 毫秒、秒级 | Storm、S4 | Spark Streaming |
基于历史数据的数据挖掘 | - | Mahout | MLlib |
图结构数据的处理 | - | Pregel、Hama | GraphX |
RDD:是Resillient Distributed Dataset(弹性分布式数据集)的简称,是分布式内存的一个抽象概念,提供了一种高度受限的共享内存模型 。
一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以被保存到集群中不同的节点上, 从而可以在集群中的不同节点上进行并行计算。
RDD提供了一种高度受限的共享内存模型,即RDD是只读的记录分区的集合,不能直接修改,只能基于稳定的物理存储中的数据集创建RDD,或者通过在其它RDD上执行确定的转换操作(如 map、join和group by)而创建得到新的RDD
RDD执行过程如下:
这一系列处理称为一个Lineage(血缘关系),即DAG拓扑排序的结果优点:惰性调用、管道化、避免同步等待、不需要保存中间结果、每次操作变得简单
1)子RDD的每个分区依赖于常数个父分区(即与数据规模无关)。
2)输入输出一对一的算子,且结果RDD的分区结构不变,如map、flatMap。
3)输入输出一对一的算子,但结果RDD的分区结构发生了变化,如union。
4)从输入中选择部分元素的算子,如filter、distinct、subtract、sample。
1)子RDD的每个分区依赖于所有父RDD分区。
2)对单个RDD基于Key进行重组和reduce,如groupByKey、reduceByKey。
3)对两个RDD基于Key进行join和重组,如join
Spark的这种依赖关系设计,使其具有了天生的容错性,大大加快了Spark的执行速度。RDD通过血缘关系记住了它是如何从其他RDD中演变过来的。当这个RDD的部分分区数据丢失时,它可以通过血缘关系获取足够的信息来重新运算和恢复丢失的数据分区,从而带来性能的提升。
Spark通过分析各个RDD的依赖关系生成了DAG,再通过分析各个RDD中的分区之间的依赖关系来决 定如何划分Stage,具体划分方法是:
Transformation
map
、flatMap
、filter、reduceByKey等。Action
take
、count
、saveAsTextFile
等。Spark运行架构包括
其中,资源管理器可以为spark自带的,也可以是Mesos或YARN等资源管理框架
一个Application由一个Driver和若干个Job构成,一个Job由多个Stage构成,一个Stage由多个没 有Shuffle关系的Task组成 。
当执行一个Application时,Driver会向集群管理器申请资源,启动Executor,并向Executor发送应用程序代码和文件,然后在Executor上执行Task,运行结束后,执行结果会返回给Driver,或者写到HDFS或者其它数据库中。
流计算是针对流数据的实时计算。
Spark Streaming是构建在Spark上的实时计算框架,且是对Spark Core API的一个扩展,它能够实现对流数据进行实时处理,并具有很好的可扩展性、高吞吐量和容错性。
Spark Streaming可整合多种输入数据源,如Kafka、Flume、HDFS,甚至是普通的TCP套接字。经处理后的数据可存储至文件系统、数据库,或显示在仪表盘里。
Spark Streaming的基本原理是将实时输入数据流以时间片(秒级)为单位进行拆分,然后经Spark引擎以类似批处理的方式处理每个时间片数据。
和Spark core的语义一致,无状态转化操作就是把简单的RDD转化操作应用到每个批次上。
那么Spark Streaming的无状态转化操作,也就是对Dstream的操作会映射到每个批次的RDD上。
无状态转换操作不会跨多个批次的RDD去执行,即每个批次的RDD结果不能累加。
有状态操作是跨时间区间跟踪处理数据的操作。依赖于之前批次的数据。
有时我们需要在DStream 中跨所有批次维护状态(例如跟踪用户访问网站的会话)。针对这种情况,updateStateByKey() 为我们提供了对一个状态变量的访问,用于键值对形式的Dstream。
使用updateStateByKey需要完成两步工作:
第一步:定义状态,状态可以是任意数据类型
第二步:定义状态更新函数- update(events, oldState)
之前我们写过的wordcount程序,我们应该发现了:单词数统计是按批次的,批次与批次互不影响,当你不断输入某个单词的时候,总的计数不会累加。那么如果想要在任意状况下都去更新某个信息,就需要使用UpdateStateByKey ,使用此功能必须执行两个步骤。
windows(窗口)函数也是一种有状态操作,基于windows的操作会在一个比StreamingContext的批次间隔更长的时间范围内,通过整合多个批次的结果,计算出整个窗口的结果。
所有基于窗口的操作都需要两个参数,分别为windowDuration
以及slideDuration
,两者都必须是StreamContext的批次间隔的整数倍。
windowDuration表示窗口框住的时间,slideDuration表示每次窗口移动的时间
间隔多久进行整合操作?slideDuration
对多少个批次进行整合?windowDuration
假设batchDuration为5秒,slideDuration为10秒,windowDuration为15秒。
1)应用场景不同
Hadoop和Spark两者都是大数据框架,但是各自应用场景是不同的。Hadoop是一个分布式数据存储架构,它将巨大的数据集分派到一个由普通计算机组成的集群中的多个节点进行存储,降低了硬件的成本。Spark是那么一个专门用来对那些分布式存储的大数据进行处理的工具,它要借助hdfs的数据存储。
2)处理速度不同
hadoop的MapReduce是分步对数据进行处理的,从磁盘中读取数据,进行一次处理,将结果写到磁盘,然后在从磁盘中读取更新后的数据,再次进行的处理,最后再将结果存入磁盘,这存取磁盘的过程会影响处理速度。spark从磁盘中读取数据,把中间数据放到内存中,,完成所有必须的分析处理,将结果写回集群,所以spark更快。
3)容错性不同
Hadoop将每次处理后的数据都写入到磁盘上,基本谈不上断电或者出错数据丢失的情况。Spark的数据对象存储在弹性分布式数据集 RDD,RDD是分布在一组节点中的只读对象集合,如果数据集一部分丢失,则可以根据于数据衍生过程对它们进行重建。而且RDD 计算时可以通过 CheckPoint 来实现容错。
我们模拟生成电商平台购买日志,然后使用Flume对日志进行收集,收集的日志一方面存入HDFS,一方面传给Kafka,Kafka收到的日志传给SparkStreaming进行实时流处理,处理的结果存入Mysql。