前言
本文先对Bulk load 银行转账记录海量冷数据存储案例做个结尾,而后介绍第三部分:HBase协处理器(Coprocessor)。
2.3.5 编写驱动类
分析:
MapReduce执行时,需要读取HBase表的region相关信息,故需要获取HBase的表
实现步骤:
1、使用HBaseConfiguration.create()加载配置文件
2、创建HBase连接
3、获取HTable
4、构建MapReduce JOB
- 使用Job.getInstance构建一个Job对象
- 调用setJarByClass设置要执行JAR包的class
- 调用setInputFormatClass为TextInputFormat.class
- 设置MapperClass
- 设置输出键Output Key Class
- 设置输出值Output Value Class
- 设置输入输出到HDFS的路径,输入路径/bank/input,输出路径/bank/output
- FileInputFormat.setInputPaths
- FileOutputFormat.setOutputPath
- 使用connection.getRegionLocator获取HBase Region的分布情况
- 使用HFileOutputFormat2.configureIncrementalLoad配置HFile输出
5、调用job.waitForCompletion执行MapReduce程序
public class BulkloadDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 加载配置文件
Configuration configuration = HBaseConfiguration.create();
// 配置JOB
Job instance = Job.getInstance(configuration);
instance.setJarByClass(BulkloadDriver.class);
instance.setMapperClass(BankRecordMapper.class);
// 配置输入
instance.setInputFormatClass(TextInputFormat.class);
FileInputFormat.setInputPaths(instance, new Path("hdfs://node1.itcast.cn:8020/bank/input"));
// 配置输出
FileOutputFormat.setOutputPath(instance, new Path("hdfs://node1.itcast.cn:8020/bank/output"));
instance.setOutputKeyClass(ImmutableBytesWritable.class);
instance.setOutputValueClass(MapReduceExtendedCell.class);
// 配置HFileoutputFormat2
Connection connection = ConnectionFactory.createConnection(configuration);
Table table = connection.getTable(TableName.valueOf("ITCAST_BANK:TRANSFER_RECORD"));
// 获取表的Region检索对象
RegionLocator regionLocator = connection.getRegionLocator(TableName.valueOf("ITCAST_BANK:TRANSFER_RECORD"));
HFileOutputFormat2.configureIncrementalLoad(instance, table, regionLocator);
// 执行job
if (instance.waitForCompletion(true)) {
System.out.println("任务执行成功!");
}
else {
System.out.println("任务执行失败!");
System.exit(1);
}
}
}
2.3.6 上传数据到文件到HDFS
将资料中的数据集 bank_record.csv 上传到HDFS的 /bank/input 目录。该文件中包含50W条的转账记录数据。hadoop fs -mkdir -p /bank/input
hadoop fs -put bank_record.csv /bank/input
然后,执行MapReduce程序。
2.3.7 加载数据文件到HBase
hbase org.apache.hadoop.hbase.tool.LoadIncrementalHFiles /bank/output ITCAST_BANK:TRANSFER_RECORD
2.3.8 MapReduce程序排错
编写MapReduce程序排错,有些是比较难找到问题的:
Exception in thread “main” java.lang.RuntimeException: java.lang.InstantiationException
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:134)
at org.apache.hadoop.mapreduce.JobSubmitter.writeNewSplits(JobSubmitter.java:299)
at org.apache.hadoop.mapreduce.JobSubmitter.writeSplits(JobSubmitter.java:318)
at org.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:196)
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1290)
at org.apache.hadoop.mapreduce.Job$10.run(Job.java:1287)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1754)
at org.apache.hadoop.mapreduce.Job.submit(Job.java:1287)
at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:1308)
at cn.itcast.bank_record.bulkload.mr1.BulkloadDriver.main(BulkloadDriver.java:53)
Caused by: java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:132)
… 11 more
上述问题,大家通过异常能找到问题吗?
见过该错误的读者,可能能看出来,但如果将来有一些问题,我们压根没见过,我们就可以尝试关联源代码来去找问题。
上述例子,我们通过关联Hadoop的源代码,就可以看出来是在:299行,在通过反射创建InputFormatClass对象时执行失败,我们看到这个就得去检查InputFormatClass的设置了。
3. HBase的协处理器(Coprocessor)
http://hbase.apache.org/book.html#cp
3.1 起源
- Hbase 作为列族数据库最经常被人诟病的特性包括:
- 无法轻易建立“二级索引”
- 难以执 行求和、计数、排序等操作
比如,在旧版本的(<0.92)Hbase 中,统计数据表的总行数,需要使用 Counter 方法,执行一次 MapReduce Job 才能得到。虽然 HBase 在数据存储层中集成了 MapReduce,能够有效用于数据表的分布式计算。然而在很多情况下,做一些简单的相加或者聚合计算的时候, 如果直接将计算过程放置在 server 端,能够减少通讯开销,从而获 得很好的性能提升
- 于是, HBase 在 0.92 之后引入了协处理器(coprocessors),实现一些激动人心的新特性:能够轻易建立二次索引、复杂过滤器(谓词下推)以及访问控制等。
3.2 协处理器有两种: observer 和 endpoint
observer协处理器
Observer 类似于传统数据库中的触发器,当发生某些事件的时候这类协处理器会被 Server 端调用。Observer Coprocessor 就是一些散布在 HBase Server 端代码中的 hook 钩子, 在固定的事件发生时被调用。比如: put 操作之前有钩子函数 prePut,该函数在 put 操作
执行前会被 Region Server 调用;在 put 操作之后则有 postPut 钩子函数
- 以 Hbase2.0.0 版本为例,它提供了三种观察者接口:
RegionObserver:提供客户端的数据操纵事件钩子: Get、 Put、 Delete、 Scan 等
WALObserver:提供 WAL 相关操作钩子。
MasterObserver:提供 DDL-类型的操作钩子。如创建、删除、修改数据表等。
- 到 0.96 版本又新增一个 RegionServerObserver
下图是以 RegionObserver 为例子讲解 Observer 这种协处理器的原理:
1.客户端发起get请求
2.该请求被分派给合适的RegionServer和Region
3.coprocessorHost拦截该请求,然后在该表上登记的每个RegionObserer上调用preGet()
4.如果没有被preGet拦截,该请求继续送到Region,然后进行处理
5.Region产生的结果再次被coprocessorHost拦截,调用posGet()处理
6.加入没有postGet()拦截该响应,最终结果被返回给客户端
endpoint协处理器
- Endpoint 协处理器类似传统数据库中的存储过程,客户端可以调用这些 Endpoint 协处理器执行一段 Server 端代码,并将 Server 端代码的结果返回给客户端进一步处理,最常见的用法就是进行聚集操作
- 如果没有协处理器,当用户需要找出一张表中的最大数据,即max 聚合操作,就必须进行全表扫描,在客户端代码内遍历扫描结果,并执行求最大值的操作。这样的方法无法利用底层集群的并发能力,而将所有计算都集中到 Client 端统一执 行,势必效率低下。
- 利用 Coprocessor,用户可以将求最大值的代码部署到 HBase Server 端,HBase 将利用底层 cluster 的多个节点并发执行求最大值的操作。即在每个 Region 范围内 执行求最大值的代码,将每个 Region 的最大值在 Region Server 端计算出,仅仅将该 max 值返回给客户端。在客户端进一步将多个 Region 的最大值进一步处理而找到其中的最大值。这样整体的执行效率就会提高很多
- 下图是 EndPoint 的工作原理:
总结- Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现
- Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令
- observer 类似于 RDBMS 中的触发器,主要在服务端工作
- endpoint 类似于 RDBMS 中的存储过程,主要在 服务器端、client 端工作
- observer 可以实现权限管理、优先级设置、监控、 ddl 控制、 二级索引等功能
- endpoint 可以实现 min、 max、 avg、 sum、 distinct、 group by 等功能
3.3 协处理器加载方式
协处理器的加载方式有两种:
静态加载方式( Static Load)
动态加载方式 ( Dynamic Load)
静态加载的协处理器称之为 System Coprocessor,动态加载的协处理器称 之为 Table Coprocessor。
静态加载
- 通过修改 hbase-site.xml 这个文件来实现
- 启动全局 aggregation,能过操纵所有的表上的数据。只需要添加如下代码:
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>
为所有 table 加载了一个 cp class,可以用” ,”分割加载多个 class
动态加载
- 启用表 aggregation,只对特定的表生效
- 通过 HBase Shell 来实现,disable 指定表
hbase> disable 'mytable'
- 添加 aggregation
hbase> alter 'mytable', METHOD => 'table_att','coprocessor'=> '|org.apache.Hadoop.hbase.coprocessor.AggregateImplementation||'
- 重启启用表
hbase> enable 'mytable'
协处理器卸载
只需三步:
disable ‘test’
alter ‘test’, METHOD => ‘table_att_unset’, NAME => ‘coprocessor$1’
enable ‘test’