本文共 3120 字,大约阅读时间需要 10 分钟。
Hbase 只是一个单纯的数据存储框架, 没有任何的分析能力.
我们可以让 Hbase 和 MapReduce 结合起来, 就扩展出来了数据分析功能.
用 MapReduce 的原因有两点:
统计的需要:
我们知道 HBase 的数据都是分布式存储在 RegionServer上的,所以对于类似传统关系型数据库的 group by 操作,扫描器是无能为力的,只有当所有结果都返回到客户端的 时候,才能进行统计。
这样做一是慢,二是会产生很大的网络开 销,所以使用 MapReduce 在服务器端就进行统计是比较好的方 案。
性能的需要:
说白了就是“快”!如果遇到较复杂的场景,在扫描器上添加多个过滤器后,扫描的性能很低;
或者当数据量很大 的时候扫描器也会执行得很慢,原因是扫描器和过滤器内部实现的机制很复杂,虽然使用者调用简单,但是服务器端的性能就不敢保证了。
在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce
HBase提供配套的TableInputFormat和TableOutPutFormat API,可以方便地将HBase Table作为Hadoop MapReduce的Source和Sink。
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实例指向了执行这些代码的集群上的这些类。
HBase中表结构由HTbleDescriptor描述(包括HColumnDescriptor),对表的新增、修改、删除操作在接口HMasterInterface中定义,而该接口由HMaster实现。
如果指定split key为该Table按指定健初始创建多个Region,否则仅创建一个Region
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。
HBase 实现的 TableOutputFormat 将输出的<key,value>对写到指定的 HBase 表中,该类不会对 WAL(Write-Ahead Log)进行操作,即如果服务器发生
故障将面临丢失数据的风险。可以使用 MultipleTableOutputFormat 类解决这个问题,该类可以对是否写入 WAL 进行设置。
转载地址:http://dnuwi.baihongyu.com/