大数据面试题知识点分析(四)

 

转自:https://blog.csdn.net/qq_26803795/article/details/79152808

为了保证效率和质量,每篇文章发布6个知识点,由简单及难,我们继续Hbase:


1)hive 跟 hbase 的区别是?

 

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

2)HBase 接收数据,如果短时间导入数量过多的话就会被锁,该怎么办?

通过调用Htable.setAutoFlush(false)方法可以将htable写客户端的自动flush关闭,这样可以批量写入到数据到hbase。而不是有一条put 就执行一次更新,只有当put填满客户端写缓存时,才实际向Hbase 服务端发起请求。默认情况下auto flush 是开启的。

3)描述 HBase 搭建过程

1.1 下载和解压
1.2 配置集群并安装ZK集群
由于HBase最终存储数据到DataNode上,故需hadoop的hdfs-site.xml、core-site.xml拷贝到hbase/conf下
1.3 修改hbase-env.sh配置文件和hbase-site.xml
修改hbase-env.sh 设置JAVA_HOME和修改HBASE_MANAGES_ZK=false,使用外部ZK.
修改hbase-site.xml 配置文件,指定hdfs存储路径和ZK
1.4 修改regionservers 配置文件
指定HRegionServer的节点,放在regionservers配置文件中
1.5 启动HBase
启动ZK
启动HDFS集群
启动HBase
需要注意的是:hbase-env.sh 配置文件,HBASE_MANAGES_ZK=false,设置外部HBase使用外部的ZK,默认情况下是true。

4)hbase 写数据的原理是什么?

客户端读取信息流程
(1)client要读取信息,先查询下client 端的cache中是否存在数据,如果存在,直接返回数据。如果不存在,则进入到zookeeper,查找到里面的相应数据存在的Root表中的地址。
(2)BlockCache;设计用于读入内存频繁访问的数据,每个列族都有。
(3)通过数据存在ROOT表中地址找到.META,最终找到HRegion。找到HRegion后,它会先访问MemStore中是否存在数据,如果存在,则直接读取。如果没有,就再到HFile中查找数据,并将数据放到MemStore。
(4)最后数据返回到客户端显示。
 
 
存储数据流程
由于Hbase中默认的刷写方式是隐式刷写,所以你在put()数据时,它会自动保存到HRegion上,但当你批量处理数据时,它会将数据先保存到client端的cache中。当你关闭隐式刷写时,你put()的数据则会保存到client cache中,直到你调用刷写命令时,才会保存到HRegion中。
 
在HRegion部分的存储:要写入的数据会先写到HMemcache和Hlog中,HMemcache建立缓存,Hlog同步Hmemcache和Hstore的事务日志,发起Flush Cache时,数据持久化到Hstore中,并清空HMemecache。
 
hbase正常写入数据时,会写入两个地方:预写式日志(WAL_or_Hlog)和Memstore(内存里的写入缓冲区), 首先写入cache,并记入WAL,然后才写入MemStore,(都写入才认为动作完成)保证数据的持久化,Hbase中的数据永久写入之前都在MemStore,当MemStore填满后,其中的数据就会写入硬盘生成HFile,
 
HBase写数据,如果在写入HStore时发生系统异常,就可以从HLog中恢复数据,重新写 HStore中。
 
Hbase的删除不会立即删除内容,会先打删除标签,直到执行一次大合并(major compaction),被删除的空间才会被释放
 
代码层次分析: HTable.put(put)
获取HTable对hTable->hTable.put(put)->put的数据存LinkedList<Row>->若AutoFlush=true,立即发送请求到服务器端,更新hbase;若AutoFlush=false,当缓冲区数据大于指定的HeadSize时,发送服务器更新hbase。
 
实际底层是开启多个线程来执行更新数据的。

 

5)hbase 宕机如何处理?

 

HLog记录数据的所有变更,一旦region server 宕机,就可以从log中进行恢复。

一个region server宕机后,zk上相应结点删除,触发RegionServerTracker的nodeDeleted(),方法调用ServerManager的expireServer逻辑,对于非meta region(0.96后只有一个meta region),提交一个ServerShutdownHanlder的任务给内部线程池处理,任务的处理逻辑在handler的process()中。HBASE-7006引入了distributed log replay特性,这里以distributed log replay为例。如果开启了distributed log replay特性,那么在zk上建立一系列结点/hbase/recovering-regions/regionEncodeName/serverName,其中regionEncodeName结点内容为该region的last flush sequence id,即这个sequence id之前的所有数据都已经flush到磁盘上产生了HFile文件,这部分数据不需要进行回放。serverName结点的内容为宕机的region server上的last flushed sequence id,即所有region中最大的last flush sequence id。将宕掉server上的region assign通过round robin的方式assign其他的活着的region server,然后提交一个LogReplayHandler的任务给内部线程池,这个任务内部就是进行split log的准备工作,将hdfs上该region server的log改名,加上-splitting后缀,变成hbase.rootdir/WALs/serverName-splitting,然后进入HMaster的SplitLogManager管理范围,在zk上建立节点,路径/hbase/splitWAL/对上面改写后的log路径的encode。然后HMaster等待log被其他region server上的SplitLogWorker split完成,然后将一开始建立的一系列节点/hbase/recovering-regions/regionEncodeName/serverName删掉,然后将-splitting目录删除.
regionserver上的SplitLogWorker会不断的去监控zk上的hbase.rootdir/WALs/serverName-splitting节点,并且试图own这个节点.成功后,则给SplitLogWorker内部线程池提交一个HLogSplitterHandler任务,任务逻辑在对象splitTaskExecutor中,任务内部主要调用HLogSplitter.splitLogFile(),从而进到HLogSplitter的boolean splitLogFile(FileStatus logfile, CancelableProgressable reporter) throws IOException. 该函数内部会读-splitting目录内部的hlog文件,然后将每条log entry加入到一个sink中,sink是一个抽象类,根据是否配置使用distributed log replay,使用不同的子类,对于distributed log replay来说,使用LogReplayOutputSink,否则使用LogRecoveredEditsOutputSink。回到函数boolean splitLogFile(FileStatus logfile, CancelableProgressable reporter) throws IOException,函数的逻辑主要是从hlog中解析出一条条的log entry,如果log entry的sequence id比zk上相应的/hbase/recovering-regions/regionEncodeName 节点记录的sequence id小,那么说明这条log entry对应的内容已经持久化在HFile中,不需要进行回放,否则将这条日志append到成员EntryBuffers对象中,EntryBuffers内部会对log entry按照region进行分组,同一个Region的log entry记录在对象RegionEntryBuffer中。同时,会有一些写线程,不断的从EntryBuffers中取出RegionEntryBuffer对象,将其append到sink中,在这里,是LogReplayOutputSink。LogReplayOutputSink中积攒到一批日志,会调用WALEditsReplaySink的replayEntries()方法,通过ReplayServerCallable这个rpc发给这个region被assign后的新的region server让其回放,由于这里使用多个写线程给其他的region server发送日志,所以叫作distributed log replay。
非distributed log replay的模式下,LogRecoveredEditsOutputSink的工作是直接按照region,把相对应的log写到hdfs的 hbase.rootdir/data/namespace(比如test)/table_name/region_encoded_name/recovered.edits下。后续region被其他region server open时,会来这看是不是有需要回放的hlog.
需要注意的是,在distributed log replay模式下,region是被open后,然后才replay ,可以看到open成功后,这个region可以提供写,但是不能提供读,因为数据不全。
以上是region server宕机后,触发的HMaster和其他region server的逻辑。


下面看看region server 收到HMaster的open region指令的逻辑。
HBase的RegionServer宕机超过一定时间后,HMaster会将其所管理的region重新分布到其他活动的RegionServer上,由于数据和日志都持久在HDFS中,
该操作不会导致数据丢失。所以数据的一致性和安全性是有保障的。
但是重新分配的region需要根据日志恢复原RegionServer中的内存MemoryStore表,这会导致宕机的region在这段时间内无法对外提供服务。
而一旦重分布,宕机的节点重新启动后就相当于一个新的RegionServer加入集群,为了平衡,需要再次将某些region分布到该server。
因此,Region Server的内存表memstore如何在节点间做到更高的可用,是HBase的一个较大的挑战。

6)如果用HBase 直接将时间戳作为行健,在写入单个 region 时候会发生热点问题,为什么?

HBase的rowkey在底层是HFile存储数据的,以键值对存放到SortedMap中。并且region中的rowkey是有序存储,若时间比较集中。就会存储到一个region中,这样一个region的数据变多,其它的region数据很好,加载数据就会很慢。直到region分裂可以解决。

 


 

posted @ 2018-08-29 19:51  流氓小伙子  阅读(299)  评论(0编辑  收藏  举报