About Hadoop

收集一些 Hadoop 相关问题。

问题

Hadoop

Yarn架构

  1. ResourceManager(RM)
    RM 是一个全局的资源管理器,负责整个系统的资源管理和分配,它主要有两个组件构成:

调度器:Scheduler;
应用程序管理器:Applications Manager,ASM。
调度器
调度器根据容量、队列等限制条件(如某个队列分配一定的资源,最多执行一定数量的作业等),将系统中的资源分配给各个正在运行的应用程序。要注意的是,该调度器是一个纯调度器,它不再从事任何与应用程序有关的工作,比如不负责重新启动(因应用程序失败或者硬件故障导致的失败),这些均交由应用程序相关的 ApplicationMaster 完成。调度器仅根据各个应用程序的资源需求进行资源分配,而资源分配单位用一个抽象概念 资源容器(Resource Container,也即 Container),Container 是一个动态资源分配单位,它将内存、CPU、磁盘、网络等资源封装在一起,从而限定每个任务使用的资源量。此外,该调度器是一个可插拔的组件,用户可根据自己的需求设计新的调度器,YARN 提供了多种直接可用的调度器,比如 Fair Scheduler 和 Capacity Schedule 等。

应用程序管理器
应用程序管理器负责管理整个系统中所有应用程序,包括应用程序提交、与调度器协商资源以 AM、监控 AM 运行状态并在失败时重新启动它等。

  1. NodeManager(NM)
    NM 是每个节点上运行的资源和任务管理器,一方面,它会定时向 RM 汇报本节点上的资源使用情况和各个 Container 的运行状态;另一方面,它接收并处理来自 AM 的 Container 启动/停止等各种请求。

  2. ApplicationMaster(AM)
    提交的每个作业都会包含一个 AM,主要功能包括:

与 RM 协商以获取资源(用 container 表示);
将得到的任务进一步分配给内部的任务;
与 NM 通信以启动/停止任务;
监控所有任务的运行状态,当任务有失败时,重新为任务申请资源并重启任务。
MapReduce 就是原生支持 ON YARN 的一种框架,可以在 YARN 上运行 MapReduce 作业。有很多分布式应用都开发了对应的应用程序框架,用于在 YARN 上运行任务,例如 Spark,Storm、Flink 等。

  1. Container
    Container 是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等,当 AM 向 RM 申请资源时,RM 为 AM 返回的资源便是用 Container 表示的。 YARN 会为每个任务分配一个 Container 且该任务只能使用该 Container 中描述的资源。

HDFS写流程

  1. Client 调用 DistributedFileSystem 对象的 create 方法,创建一个文件输出流(FSDataOutputStream)对象;
  2. 通过 DistributedFileSystem 对象与集群的 NameNode 进行一次 RPC 远程调用,在 HDFS 的 Namespace 中创建一个文件条目(Entry),此时该条目没有任何的 Block,NameNode 会返回该数据每个块需要拷贝的 DataNode 地址信息;
  3. 通过 FSDataOutputStream 对象,开始向 DataNode 写入数据,数据首先被写入 FSDataOutputStream 对象内部的数据队列中,数据队列由 DataStreamer 使用,它通过选择合适的 DataNode 列表来存储副本,从而要求 NameNode 分配新的 block;
  4. DataStreamer 将数据包以流式传输的方式传输到分配的第一个 DataNode 中,该数据流将数据包存储到第一个 DataNode 中并将其转发到第二个 DataNode 中,接着第二个 DataNode 节点会将数据包转发到第三个 DataNode 节点;
  5. DataNode 确认数据传输完成,最后由第一个 DataNode 通知 client 数据写入成功;
  6. 完成向文件写入数据,Client 在文件输出流(FSDataOutputStream)对象上调用 close 方法,完成文件写入;
  7. 调用 DistributedFileSystem 对象的 complete 方法,通知 NameNode 文件写入成功,NameNode 会将相关结果记录到 editlog 中。

HDFS读流程

  1. Client 通过 DistributedFileSystem 对象与集群的 NameNode 进行一次 RPC 远程调用,获取文件 block 位置信息;
  2. NameNode 返回存储的每个块的 DataNode 列表;
  3. Client 将连接到列表中最近的 DataNode;
  4. Client 开始从 DataNode 并行读取数据;
  5. 一旦 Client 获得了所有必须的 block,它就会将这些 block 组合起来形成一个文件。

HDFS创建一个文件的流程

  1. 客户端通过ClientProtocol协议向RpcServer发起创建文件的RPC请求。
  2. FSNamesystem封装了各种HDFS操作的实现细节,RpcServer调用FSNamesystem中的相关方法以创建目录。
  3. 进一步的,FSDirectory封装了各种目录树操作的实现细节,FSNamesystem调用FSDirectory中的相关方法在目录树中创建目标文件,并通过日志系统备份文件系统的修改。
  4. 最后,RpcServer将RPC响应返回给客户端。

Hadoop1.x与Hadoop2.x的区别

Hadoop1.x的缺点:
JobTracker存在单点故障的隐患
任务调度和资源管理全部是JobTracker来完成,单点负担过重
TaskTracker以Map/Reduce数量表示资源太过简单
TaskTracker 分Map Slot 和 Reduce Slot, 如果任务只需要map任务可能会造成资源浪费

  1. 资源调度方式的改变
    在1.x, 使用Jobtracker负责任务调度和资源管理,单点负担过重,在2.x中,新增了yarn作为集群的调度工具.在yarn中,使用ResourceManager进行 资源管理, 单独开启一个Container作为ApplicationMaster来进行任务管理.
  2. HA模式
    在1.x中没有HA模式,集群中只有一个NameNode,而在2.x中可以启用HA模式,存在一个Active NameNode 和Standby NameNode.
  3. HDFS Federation
    Hadoop 2.0中对HDFS进行了改进,使NameNode可以横向扩展成多个,每个NameNode分管一部分目录,进而产生了HDFS Federation,该机制的引入不仅增强了HDFS的扩展性,也使HDFS具备了隔离性

Hadoop HA的介绍

  1. Active NameNode 和 Standby NameNode:两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务;
  2. ZKFailoverController(主备切换控制器,FC):ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换(当然 NameNode 目前也支持不依赖于 Zookeeper 的手动主备切换);
  3. Zookeeper 集群:为主备切换控制器提供主备选举支持;
  4. 共享存储系统:共享存储系统是实现 NameNode 的高可用最为关键的部分,共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。主 NameNode 和备 NameNode 通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主 NameNode 在确认元数据完全同步之后才能继续对外提供服务。
  5. DataNode 节点:因为主 NameNode 和备 NameNode 需要共享 HDFS 的数据块和 DataNode 之间的映射关系,为了使故障切换能够快速进行,DataNode 会同时向主 NameNode 和备 NameNode 上报数据块的位置信息。

描述如何安装配置Hadoop

  1. 使用root账户登录
  2. 修改IP
  3. 修改Host主机名
  4. 配置SSH免密码登录
  5. 关闭防火墙
  6. 安装JDK
  7. 解压hadoop安装包
  8. 配置hadoop的核心文件
    hadoop-env.sh:用于定义Hadoop运行环境相关的配置信息,比如配置JAVA_HOME环境变量、为Hadoop的JVM指定特定的选项、指定日志文件所在的目录路径以及master和slave文件的位置等;
    core-site.xml:用于定义系统级别的参数,如HDFS URL、Hadoop的临时目录以及用于rack-aware集群中的配置文件的配置等,此中的参数定义会覆盖core-default.xml文件中的默认配置;
    mapred-site.xml:HDFS的相关设定,如reduce任务的默认个数、任务所能够使用内存的默认上下限等,此中的参数定义会覆盖mapred-default.xml文件中的默认配置;
    hdfs-site.xml:HDFS的相关设定,如文件副本的个数、块大小及是否使用强制权限等,此中的参数定义会覆盖hdfs-default.xml文件中的默认配置;
  9. 格式化 hadoop namenode -format
  10. 启动节点start-all.sh

启动Hadoop集群会分别启动哪些进程,各自的作用?

  1. NameNode:
    维护文件系统树及整棵树内所有的文件和目录。这些信息永久保存在本地磁盘的两个文件中:命名空间镜像文件、编辑日志文件
    记录每个文件中各个块所在的数据节点信息,这些信息在内存中保存,每次启动系统时重建这些信息
    负责响应客户端的 数据块位置请求 。也就是客户端想存数据,应该往哪些节点的哪些块存;客户端想取数据,应该到哪些节点取
    接受记录在数据存取过程中,datanode节点报告过来的故障、损坏信息

  2. SecondaryNameNode(非HA模式):
    实现namenode容错的一种机制。定期合并编辑日志与命名空间镜像,当namenode挂掉时,可通过一定步骤进行上顶。(注意 并不是NameNode的备用节点)

  3. DataNode:
    根据需要存取并检索数据块
    定期向namenode发送其存储的数据块列表

  4. ResourceManager:
    负责Job的调度,将一个任务与一个NodeManager相匹配。也就是将一个MapReduce之类的任务分配给一个从节点的NodeManager来执行。

  5. NodeManager:
    运行ResourceManager分配的任务,同时将任务进度向application master报告

  6. JournalNode(HA下启用):
    高可用情况下存放namenode的editlog文件

小文件过多会有什么危害?

Hadoop上大量HDFS元数据信息存储在NameNode内存中,因此过多的小文件必定会压垮NameNode的内存.
每个元数据对象约占150byte,所以如果有1千万个小文件,每个文件占用一个block,则NameNode大约需要2G空间。如果存储1亿个文件,则NameNode需要20G空间.
显而易见的解决这个问题的方法就是合并小文件,可以选择在客户端上传时执行一定的策略先合并,或者是使用Hadoop的CombineFileInputFormat<K,V>实现小文件的合并

Hive

Hive内部表和外部表的区别

建表时带有external关键字为外部表,否则为内部表
内部表和外部表建表时都可以自己指定location
删除表时,外部表不会删除对应的数据,只会删除元数据信息,内部表则会删除
其他用法是一样的

Hive四种排序方式的区别

  • order by
    order by 是要对输出的结果进行全局排序,这就意味着只有一个reducer才能实现(多个reducer无法保证全局有序)但是当数据量过大的时候,效率就很低。如果在严格模式下(hive.mapred.mode=strict),则必须配合limit使用

  • sort by
    sort by 不是全局排序,只是在进入到reducer之前完成排序,只保证了每个reducer中数据按照指定字段的有序性,是局部排序。配置mapred.reduce.tasks=[nums]可以对输出的数据执行归并排序。可以配合limit使用,提高性能

  • distribute by
    distribute by 指的是按照指定的字段划分到不同的输出reduce文件中,和sort by一起使用时需要注意, distribute by必须放在前面

  • cluster by
    cluster by 可以看做是一个特殊的distribute by+sort by,它具备二者的功能,但是只能实现倒序排序的方式,不能指定排序规则为asc 或者desc

Hive的Metastore的三种模式

  • 内嵌Derby方式
    这个是Hive默认的启动模式,一般用于单元测试,这种存储方式有一个缺点:在同一时间只能有一个进程连接使用数据库。

  • Local方式
    本地MySQL

  • Remote方式
    远程MySQL,一般常用此种方式

Hive中的join有哪些?

Hive中除了支持和传统数据库中一样的内关联(JOIN)、左关联(LEFT JOIN)、右关联(RIGHT JOIN)、全关联(FULL JOIN),还支持左半关联(LEFT SEMI JOIN)

  • 内关联(JOIN)
    只返回能关联上的结果。

  • 左外关联(LEFT [OUTER] JOIN)
    以LEFT [OUTER] JOIN关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段置为NULL。

  • 右外关联(RIGHT [OUTER] JOIN)
    和左外关联相反,以RIGTH [OUTER] JOIN关键词后面的表作为主表,和前面的表做关联,返回记录数和主表一致,关联不上的字段为NULL。

  • 全外关联(FULL [OUTER] JOIN)
    以两个表的记录为基准,返回两个表的记录去重之和,关联不上的字段为NULL。

  • LEFT SEMI JOIN
    以LEFT SEMI JOIN关键字前面的表为主表,返回主表的KEY也在副表中的记录

  • 笛卡尔积关联(CROSS JOIN)
    返回两个表的笛卡尔积结果,不需要指定关联键。

Impala和Hive的查询有哪些区别?

Impala是基于Hive的大数据实时分析查询引擎,直接使用Hive的元数据库Metadata,意味着impala元数据都存储在Hive的metastore中。并且impala兼容Hive的sql解析,实现了Hive的SQL语义的子集,功能还在不断的完善中。

Impala相对于Hive所使用的优化技术

  1. 没有使用 MapReduce进行并行计算,虽然MapReduce是非常好的并行计算框架,但它更多的面向批处理模式,而不是面向交互式的SQL执行。与 MapReduce相比:Impala把整个查询分成一执行计划树,而不是一连串的MapReduce任务,在分发执行计划后,Impala使用拉式获取 数据的方式获取结果,把结果数据组成按执行树流式传递汇集,减少的了把中间结果写入磁盘的步骤,再从磁盘读取数据的开销。Impala使用服务的方式避免 每次执行查询都需要启动的开销,即相比Hive没了MapReduce启动时间。
  2. 使用LLVM产生运行代码,针对特定查询生成特定代码,同时使用Inline的方式减少函数调用的开销,加快执行效率。
  3. 充分利用可用的硬件指令(SSE4.2)。
  4. 更好的IO调度,Impala知道数据块所在的磁盘位置能够更好的利用多磁盘的优势,同时Impala支持直接数据块读取和本地代码计算checksum。
  5. 通过选择合适的数据存储格式可以得到最好的性能(Impala支持多种存储格式)。
  6. 最大使用内存,中间结果不写磁盘,及时通过网络以stream的方式传递。

Hive中大表join小表的优化

在小表和大表进行join时,将小表放在前边,效率会高,hive会将小表进行缓存

Hive Sql是怎样解析成MR job的?

主要分为6个阶段:

  1. Hive使用Antlr实现语法解析.根据Antlr制定的SQL语法解析规则,完成SQL语句的词法/语法解析,将SQL转为抽象语法树AST.
  2. 遍历AST,生成基本查询单元QueryBlock.QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出.
  3. 遍历QueryBlock,生成OperatorTree.Hive最终生成的MapReduce任务,Map阶段和Reduce阶段均由OperatorTree组成。Operator就是在Map阶段或者Reduce阶段完成单一特定的操作。QueryBlock生成Operator Tree就是遍历上一个过程中生成的QB和QBParseInfo对象的保存语法的属性.
  4. 优化OperatorTree.大部分逻辑层优化器通过变换OperatorTree,合并操作符,达到减少MapReduce Job,减少shuffle数据量的目的
  5. OperatorTree生成MapReduce Job.遍历OperatorTree,翻译成MR任务.
    对输出表生成MoveTask
    从OperatorTree的其中一个根节点向下深度优先遍历
    ReduceSinkOperator标示Map/Reduce的界限,多个Job间的界限
    遍历其他根节点,遇过碰到JoinOperator合并MapReduceTask
    生成StatTask更新元数据
    剪断Map与Reduce间的Operator的关系
  6. 优化任务. 使用物理优化器对MR任务进行优化,生成最终执行任务

Hive UDF简单介绍

在Hive中,用户可以自定义一些函数,用于扩展HiveQL的功能,而这类函数叫做UDF(用户自定义函数)。UDF分为两大类:UDAF(用户自定义聚合函数)和UDTF(用户自定义表生成函数)。
Hive有两个不同的接口编写UDF程序。一个是基础的UDF接口,一个是复杂的GenericUDF接口。
org.apache.hadoop.hive.ql. exec.UDF 基础UDF的函数读取和返回基本类型,即Hadoop和Hive的基本类型。如,Text、IntWritable、LongWritable、DoubleWritable等。
org.apache.hadoop.hive.ql.udf.generic.GenericUDF 复杂的GenericUDF可以处理Map、List、Set类型。

按照学生科目取每个科目的TopN

原始数据:

1
2
3
4
5
6
7
8
9
id,name,subject,score
1,小明,语文,87
2,张三,语文,27
3,王五,语文,69
4,李四,语文,99
5,小明,数学,86
6,马六,数学,33
7,李四,数学,44
8,小红,数学,50

sql:

1
2
3
select a.* from
(select id,name,subject,score,row_number() over(partition by subject order by score desc) rank from student) a
where a.rank <= 3

Spark

讲一下Spark的运行架构


Cluster Manager(Master):在standalone模式中即为Master主节点,控制整个集群,监控worker。在YARN模式中为资源管理器
Worker节点:从节点,负责控制计算节点,启动Executor或者Driver。
Driver: 运行Application 的main()函数
Executor:执行器,是为某个Application运行在worker node上的一个进程

一个Spark程序的执行流程

A -> 当 Driver 进程被启动之后,首先它将发送请求到Master节点上,进行Spark应用程序的注册
B -> Master在接受到Spark应用程序的注册申请之后,会发送给Worker,让其进行资源的调度和分配.
C -> Worker 在接受Master的请求之后,会为Spark应用程序启动Executor, 来分配资源
D -> Executor启动分配资源好后,就会想Driver进行反注册,这是Driver已经知道哪些Executor为他服务了
E -> 当Driver得到注册了Executor之后,就可以开始正式执行spark应用程序了. 首先第一步,就是创建初始RDD,读取数据源,再执行之后的一系列算子. HDFS文件内容被读取到多个worker节点上,形成内存中的分布式数据集,也就是初始RDD
F -> Driver就会根据 Job 任务任务中的算子形成对应的task,最后提交给 Executor, 来分配给task进行计算的线程
G -> task就会去调用对应的任务数据来计算,并task会对调用过来的RDD的partition数据执行指定的算子操作,形成新的RDD的partition,这时一个大的循环就结束了
后续的RDD的partition数据又通过Driver形成新的一批task提交给Executor执行,循环这个操作,直到所有的算子结束

HBase

HBase的架构和基本原理

Hbase以表的方式组织数据,
表由行(Row)以及列(Column)组成,行由row key和一个或多个列及其值组成(存储是按照row key的字典顺序排序,row key的设计非常重要!!),
列必须属于某一列族(Column family),一个列族可以有一各或多个列(一列由列簇和列修饰符组成,他们通常由冒号(:) 分隔),其在存储架构中就是一个Hfile。
Hbase中的列可以达到百万级,列中的数据可以是稀疏的,空值并不占用存储空间。
数据按主键排序,同时表按主键划分为多个Region。底层是LSM树(Long-Structed Merge Tree)。

对于以上叙述,表的简略结构(逻辑模型):

HBase简略架构图:

接下来对Zookeeper、HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog做简单叙述。

Zookeeper
  • 保证任何时候,集群中只有一个master(负责多HMaster的选举)
  • 存贮所有Region的寻址入口
  • 实时监控RegionServer的状态,将RegionServer的上线和下线信息实时通知给Master(服务器之间状态同步)
  • 存储HBase的schema(元数据信息)。包括有哪些table、每个table有哪些column family等
HMaster

主要负责table和region的管理工作。

  • Region分裂后,为RegionServer分配新的Region
  • 负责RegionServer的负载均衡,调整region的分配
  • 发现失效的RegionServer,并重新分配其上的region
  • 管理用户对table的增、删、改、查操作
  • 监听zk,基于zookeeper感应rs的上下线
  • 监听zk,基于zookeeper来保证HA
  • 处理schema更新请求(管理用户对表的增删改)
  • 不参与对表的读写访问
  • 负载很低
  • 无单点故障
  • 在一个RegionServer死机后,负责失效节点的Region迁移
HRegionServer

主要负责响应用户对其上region的I/O请求,向HDFS读写数据。

  • HRegionServer维护HMaster分配给它的region
  • 维护region的cache
  • 处理region的flush、compact、split
  • 内部管理一系列的HRegion对象
  • 一个HRegionServer会有多个HRegion和一个HLog
HRegion

也就是指一个Table的分区。

  • 每一个HRegion又由很多的Store组成,每一个Store存储的实际上是一个列簇(ColumnFamily)下所有的数据。此外,在每一个Store(又名HStore)中有包含一块MemStore。MemStore驻留在内存中,数据到来时首先更新到MemStore中,当到达阈值之后再flush(默认64M)到对应的StoreFile(又名HFile)中,所以每一个Store包含多个StoreFile,StoreFile负责的是实际数据存储,为HBase中最小的存储单元。
  • 达到某个阈值时,分裂(默认256M)。所以一个HRegionServer管理多个表,一个表下有多个Region,一个HRegion有多少个列族就有多少个Store,Store下有多个StoreFile文件,是HBase中最小的存储单元。
  • 以Region为单位管理, region(startKey,endKey);【默认情况下,刚创建一个表时,并不知道startkey和endkey】
  • 每个Column Family单独存储:storeFile;( storefile的数量一多(到达阀值),就合并(同时合并版本以及删除之前要删除的数据);合并后大小到达阀值就split)
  • 当某个Column Family累积的大小(具体的数据量) > 某阈值时,自动分裂成两个Region;合并之后,旧数据也不是立即删除,而是复制一份并同内存中的数据一起写到磁盘,在之后,LSM-Tree会提供一些机制来回收这些空间。
  • 如何找到某行属于哪个region呢?两张特殊的表:-NAMESPACE- 和.META.
StoreFile

底层存储格式是HFile,HBase中最小的存储单元。memStore内存中的数据写到文件后就是StoreFile,StoreFile底层是以HFile的格式保存。

HFile
  • HBase中KeyValue数据的存储格式,是hadoop的二进制格式文件。
  • HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。
  • Trailer中有指针指向其他数据块的起始点,FileInfo记录了文件的一些meta信息。 - Data Block是hbase io的基本单元,为了提高效率,HRegionServer中有基于LRU的block cache机制。
  • 每个Data块的大小可以在创建一个Table的时候通过参数指定(默认块大小64KB),大号的Block有利于顺序Scan,小号的Block利于随机查询。
  • 每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成
  • Magic内容就是一些随机数字,目的是防止数据损坏

HLog

HLog是WAL的核心实现类。

  • WAL意为write ahead log,HBase中的预写日志,用来做灾难恢复使用,底层实现是HLog,HLog记录数据的所有变更。使用WAL的原因:因为MemStore存储的数据是驻留在内存中的,是不稳定的(比如宕机时),所以采用了WAL预写日志来解决这个问题。(运行MApReduce作业时,可以通过关闭WAL功能来获得性能的提升——setWriteToWAL(boolean))
  • 其实HLog文件就是一个普通的Hadoop Sequence File, Sequence File的value是key时HLogKey对象,其中记录了写入数据的归属信息,除了table和region名字外,还同时包括sequence number和timestamp,timestamp是写入时间,sequence number的起始值为0,或者是最近一次存入文件系统中的sequence number。 Sequence File的value是HBase的KeyValue对象,即对应HFile中的KeyValue。[1]
与传统关系型数据库的区别

数据类型:没有数据类型,都是字节数组(有一个工具类Bytes,将java对象序列化为字节数组)。
数据操作:HBase只有很简单的插入、查询、删除、清空等操作,表和表之间是分离的,没有复杂的表和表之间的关系,而传统数据库通常有各式各样的函数和连接操作。
存储模式:Hbase适合于非结构化数据存储,基于列存储而不是行。
数据维护:HBase的更新操作不应该叫更新,它实际上是插入了新的数据,而传统数据库是替换修改
时间版本:Hbase数据写入cell时,还会附带时间戳,默认为数据写入时RegionServer的时间,但是也可以指定一个不同的时间。数据可以有多个版本。
可伸缩性,Hbase这类分布式数据库就是为了这个目的而开发出来的,所以它能够轻松增加或减少硬件的数量,并且对错误的兼容性比较高。而传统数据库通常需要增加中间层才能实现类似的功能

HBase的应用场景
  • 半结构化或非结构化数据:
    对于数据结构字段不够确定或杂乱无章非常难按一个概念去进行抽取的数据适合用HBase,因为HBase支持动态添加列。
  • 记录很稀疏:
    RDBMS的行有多少列是固定的。为null的列浪费了存储空间。而如上文提到的,HBase为null的Column不会被存储,这样既节省了空间又提高了读性能。
  • 多版本号数据:
    依据Row key和Column key定位到的Value能够有随意数量的版本号值,因此对于须要存储变动历史记录的数据,用HBase是很方便的。比方某个用户的Address变更,用户的Address变更记录也许也是具有研究意义的。
  • 仅要求最终一致性:
    对于数据存储事务的要求不像金融行业和财务系统这么高,只要保证最终一致性就行。(比如HBase+elasticsearch时,可能出现数据不一致)
  • 高可用和海量数据以及很大的瞬间写入量:
    WAL解决高可用,支持PB级数据,put性能高
    索引插入比查询操作更频繁的情况。比如,对于历史记录表和日志文件。(HBase的写操作更加高效)
  • 业务场景简单:
    不需要太多的关系型数据库特性,列入交叉列,交叉表,事务,连接等。

HBase 宕机如何处理?

宕机分为HMaster宕机和HRegionServer宕机,如果是HRegionServer宕机,HMaster会将其所管理的region重新分布到其他活动的RegionServer上,由于数据和日志都持久在HDFS中,该操作不会导致数据丢失。所以数据的一致性和安全性是有保障的。

如果是HMaster宕机,HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。即Zookeeper会保证总会有一个HMaster在对外提供服务。

HRegionServer宕机如何处理?

  • ZooKeeper 会监控 HRegionServer 的上下线情况,当 ZK 发现某个 HRegionServer 宕机之后会通知 HMaster 进行失效备援;
  • HRegionServer 会停止对外提供服务,就是它所负责的 region 暂时停止对外提供服务
  • HMaster 会将该 HRegionServer 所负责的 region 转移到其他 HRegionServer 上,并且会对 HRegionServer 上存在 memstore 中还未持久化到磁盘中的数据进行恢复;
  • 这个恢复的工作是由 WAL重播 来完成,这个过程如下:
    wal实际上就是一个文件,存在/hbase/WAL/对应RegionServer路径下
    宕机发生时,读取该RegionServer所对应的路径下的wal文件,然后根据不同的region切分成不同的临时文件recover.edits
    当region被分配到新的RegionServer中,RegionServer读取region时会进行是否存在recover.edits,如果有则进行恢复

HBase写数据的流程

  • Client先访问zookeeper,从.META.表获取相应region信息,然后从meta表获取相应region信息
  • 根据namespace、表名和rowkey根据meta表的数据找到写入数据对应的region信息
  • 找到对应的regionserver 把数据先写到WAL中,即HLog,然后写到MemStore上
  • MemStore达到设置的阈值后则把数据刷成一个磁盘上的StoreFile文件。
  • 当多个StoreFile文件达到一定的大小后(这个可以称之为小合并,合并数据可以进行设置,必须大于等于2,小于10——hbase.hstore.compaction.max和hbase.hstore.compactionThreshold,默认为10和3),会触发Compact合并操作,合并为一个StoreFile,(这里同时进行版本的合并和数据删除。)
  • 当Storefile大小超过一定阈值后,会把当前的Region分割为两个(Split)【可称之为大合并,该阈值通过hbase.hregion.max.filesize设置,默认为10G】,并由Hmaster分配到相应的HRegionServer,实现负载均衡

HBase读数据的流程

  • 首先,客户端需要获知其想要读取的信息的Region的位置,这个时候,Client访问hbase上数据时并不需要Hmaster参与(HMaster仅仅维护着table和Region的元数据信息,负载很低),只需要访问zookeeper,从meta表获取相应region信息(地址和端口等)。【Client请求ZK获取.META.所在的RegionServer的地址。】
  • 客户端会将该保存着RegionServer的位置信息的元数据表.META.进行缓存。然后在表中确定待检索rowkey所在的RegionServer信息(得到持有对应行键的.META表的服务器名)。【获取访问数据所在的RegionServer地址】
  • 根据数据所在RegionServer的访问信息,客户端会向该RegionServer发送真正的数据读取请求。服务器端接收到该请求之后需要进行复杂的处理。
  • 先从MemStore找数据,如果没有,再到StoreFile上读(为了读取的效率)。

HBase和Hive有什么区别?Hive与HBase的底层存储是什么?Hive产生的原因是什么?HBase是为了弥补Hadoop的什么缺陷?

共同点:
都是架构在hadoop之上的,都是用Hadoop作为底层存储

区别:
- Hive是建立在Hadoop之上为了减少MapReducejobs编写工作的批处理系统,HBase是为了支持弥补Hadoop对实时操作的缺陷的项目 。
- 想象你在操作RMDB数据库,如果是全表扫描,就用Hive+Hadoop,如果是索引访问,就用HBase+Hadoop;
- Hive query就是MapReduce jobs可以从5分钟到数小时不止,HBase是非常高效的,肯定比Hive高效的多;
- Hive本身不存储和计算数据,它完全依赖于 HDFS 和 MapReduce,Hive中的表纯逻辑;
- hive借用hadoop的MapReduce来完成一些hive中的命令的执行;
- hbase是物理表,不是逻辑表,提供一个超大的内存hash表,搜索引擎通过它来存储索引,方便查询操作;
- hbase是列存储;
- hdfs 作为底层存储,hdfs 是存放文件的系统,而 Hbase 负责组织文件;
- hive 需要用到 hdfs 存储文件,需要用到 MapReduce 计算框架。

解释下HBase实时查询的原理

实时查询,可以认为是从内存中查询,一般响应时间在 1 秒内。HBase 的机制是数据先写入到内存中,当数据量达到一定的量(如 128M),再写入磁盘中, 在内存中,是不进行数据的更新或合并操作的,只增加数据,这使得用户的写操作只要进入内存中就可以立即返回,保证了 HBase I/O 的高性能。

描述HBase的rowkey的设计

联系region和rowkey关系说明,设计可参考以下三个原则:

  1. rowkey长度原则

rowkey 是一个二进制码流,可以是任意字符串,最大长度 64kb,实际应用中一般为 10-100bytes,以 byte[] 形式保存,一般设计成定长。建议越短越好,不要超过 16 个字节, 原因如下:

数据的持久化文件 HFile 中是按照 KeyValue 存储的,如果 rowkey 过长会极大影响 HFile 的存储效率 MemStore 将缓存部分数据到内存,如果 rowkey 字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。

  1. rowkey散列原则

如果 rowkey 按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将 rowkey 的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个 RegionServer,以实现负载均衡的几率。如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个 RegionServer 上,这样在数据检索的时候负载会集中在个别的 RegionServer 上,造成热点问题,会降低查询效率。

  1. rowkey唯一原则

必须在设计上保证其唯一性,rowkey 是按照字典顺序排序存储的,因此, 设计 rowkey 的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。

描述HBase中scan和get的功能以及实现的异同

  • 按指 定 RowKey 获 取 唯 一 一 条 记 录 , get 方法( org.apache.hadoop.hbase.client.Get ) Get的方法处理分两种 : 设置了ClosestRowBefore和没有设置的 rowlock 主要是用来保证行的事务性,即每个get 是以一个 row 来标记的.一个 row 中可以有很多 family 和 column。
  • 按指定的条件获取一批记录,scan 方法(org.apache.Hadoop.hbase.client.Scan)实现条件查询功能使用的就是 scan 方式
    scan 可以通过 setCaching 与 setBatch 方法提高速度(以空间换时间);
    scan 可以通过 setStartRow 与 setEndRow 来限定范围([start,end]start? 是闭区间,end 是开区间)。范围越小,性能越高;
    scan 可以通过 setFilter 方法添加过滤器,这也是分页、多条件查询的基础。 3.全表扫描,即直接扫描整张表中所有行记录。

简述HBase中的compact的用途?什么时候触发?分为哪两种?

在 HBase 中每当有 memstore 数据 flush 到磁盘之后,就形成一个 storefile, 当 storeFile 的数量达到一定程度后,就需要将 storefile 文件来进行 compaction 操作。Compact 的作用:

合并文件
清除过期,多余版本的数据
提高读写数据的效率

  • Minor操作
    只合并小文件,对TTL过期数据设置过期清理,不会对文件内容进行清除操作。

  • Major操作
    对 Region 下同一个 Column family 的 StoreFile 合并为一个大文件,并且清除删除、过期、多余版本的数据。