Hbase 和 MapReduce 结合

Hbase 只是一个单纯的数据存储框架, 没有任何的分析能力.

我们可以让 Hbase 和 MapReduce 结合起来, 就扩展出来了数据分析功能.

为什么需要使用 MapReduce

用 MapReduce 的原因有两点:

  • 统计的需要:

    我们知道 HBase 的数据都是分布式存储在 RegionServer上的,所以对于类似传统关系型数据库的 group by 操作,扫描器是无能为力的,只有当所有结果都返回到客户端的 时候,才能进行统计。

    这样做一是慢,二是会产生很大的网络开 销,所以使用 MapReduce 在服务器端就进行统计是比较好的方 案。

  • 性能的需要:

    说白了就是“快”!如果遇到较复杂的场景,在扫描器上添加多个过滤器后,扫描的性能很低;

    或者当数据量很大 的时候扫描器也会执行得很慢,原因是扫描器和过滤器内部实现的机制很复杂,虽然使用者调用简单,但是服务器端的性能就不敢保证了。

在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce

HBase提供配套的TableInputFormat和TableOutPutFormat API,可以方便地将HBase Table作为Hadoop MapReduce的Source和Sink。

1.HBaseConfiguration类

org.apache.hadoop.hbase.HbaseConfiguration继承了org.apache.hadoop.conf.Configuration类,创建一个HBaseConfiguration读写实例,会返回读入CLASSPATH下hbase.site.xml文件和hbase-default.xml文件中的HBase配制信息的一个Configuration,该Configuration接下来会用于创建HBaseAdmin和HTable实例

HBaseAdmin和HTale两个类在org.apache.hadooop.hbase.client包中。HBase Admin用于管理HBase集群、添加、删除表,HTable用于访问指定的表,Configuration实例指向了执行这些代码的集群上的这些类。

2.HTalbeDescriptor类和HColumnDescriptor类

HBase中表结构由HTbleDescriptor描述(包括HColumnDescriptor),对表的新增、修改、删除操作在接口HMasterInterface中定义,而该接口由HMaster实现。

3.createTable方法

如果指定split key为该Table按指定健初始创建多个Region,否则仅创建一个Region

4.TableInputFormat类

TableInputFormat继承TableInputFormatBase实现了InputFormat抽象类的两个抽象方法getSplit()和createRecordReader().

两个核心方法:
getSplits():断定输入对象的切分原则,原则是对于TableInputFormatBase,会遍历HBase相应表的所有HRegion,每一个HRegion都会被切分成一个Split,所有切分的块数与表中HRegion的数目是相同的,代码如下:

InputSplit split = new TableSplit(table.getTableName(),splitStart,splitStop,regionLocation);

在Split中只会记载HRegion的起始Row Key和结束Row Key,具体去读取这片区域的数据是createRecordReader()实现的。

对于一个Map任务,JobTracker会考虑TaskTracker的网络位置,并选取一个距离其输入分片文件最近的TaskTracker。在理想情况下,任务是数据本地化的,也就是;任务运行在输入分片所在的节点上。同样,任务也可能是及其本地化的:任务和输入分片在同一个机架,但不在同一个节点上。

对于Reduce任务,JobTracker简单地从待运行的Reduce任务列表中选取下一个来运行,用不着考虑数据段本地化。

createRecordReader()按照必然格式读取响应数据,接收split块,返回split块,返回读取记录的结果,操作代码如下:

public RecordReader<ImmutableBytesWritable,Result> createRecordReader(InputSplit split,TaskAttemptContext context){

          Scan scan = new Scan(this.scan);

          scan.setStartRow(tableSplit.getStartRow());

          scan.setStopRow(tableSplit.getEndRow());

          tableRecorderReader.setScan(scan);

          talbeRecorderReader.setHTble(table);

          tableRecorderReader.init();

          return tableRecorderReader;

}

 talbeRecorderReader.init()返回的是这个分块的起始Row  Key的记录;RecordReader将一个Split解析成<key,value>的形式提供给map函数,key就是Row Key,Value就是对应的一行数据。

RecordReader用于在划分中读取<key,value>对。RecordReader有5个虚方法,下面分别进行介绍。

initialize:初始化,输入参数包括该Reader工作的数据划分InputSplit和Job的上下context。

nextKey:得到输入的下一个Key,如果数据划分已经没有新的记录,返回空。

nextVelue:得到Key对应的Value,必须在调用nextKey后调用。

getProgress:得到现在的进度。

close:得到来自java.io的Closeable接口,用于清理RecordReader。

在MapReduce驱动中调用TableInputFormat的类:

job.setInputFormatClass(TableInputFormat.class);

使用以下方法就不需要再单独定义。

tableMapReduceUtil.initTableReducerJob("daily_result",DailyReduce.class,job);

initTableReducerJob()方法完成一系列操作。

1)job.setOutputFormatClass(TableOutputFormat.class);设置输出格式。

2)conf.set(TableOutputFormat.OUTPUT_TABLE,table);设置输出表。

3)初始化partition。

TableOutputFormat

HBase 实现的 TableOutputFormat 将输出的<key,value>对写到指定的 HBase 表中,该类不会对 WAL(Write-Ahead  Log)进行操作,即如果服务器发生
故障将面临丢失数据的风险。可以使用 MultipleTableOutputFormat 类解决这个问题,该类可以对是否写入 WAL 进行设置。
 

猜你喜欢

转载自blog.csdn.net/qq_43193797/article/details/86654011