前言
近半年本人主要在倒腾数据,遇到海量数据去重的难题,曾经尝试过各种hivesql,然而随着数据量逐渐增大,处理耗时也越来越长,各种方案一一破产。2012年11月份提过使用HBase唯一主键的方案,随即做了相关预研(参看hive&hbase解决方案测评)。该方案由于HBase转化成hive表性能问题而搁浅。但在测评报告最后的总结中提到:或许我们可以选择数据“冷热”、以及部分字段切表来优化。
2013年3月,我们在业务上做了调整,通过部分字段来区分数据的“冷热”,从此希望的烟火重新燃起……
表设计
为区分数据的“冷热”,我们采用分表方式,即冷数据A和热数据B存储于HBase的不同表,另外每天增量数据的冷数据C也有一张表来存储。相对而言,B、C两张表数据量不大,顶多上千万条记录,A才是可能成为海量(TB、PB级别)的数据表。3张表的设计缺点是增量数据导入时业务复杂,需要经过多次判断。
导入
数据导入HBase及hive时遇到了几个问题,一一道来。
数据在数量级别上分两种,一种是初始化大数据量数据,另一种是常态化增量小数据量数据。两种数据导入HBase时需要采取不同的策略。
初始化数据
我们有3亿+的初始化数据,对于海量数据存储大吞吐量写入的HBase来说是小case(根据各种测评得出的结论)。原先采用MapRedue按行读取hdfs文件数据,直接put至HBase表中方式。该方式是很普遍很通用的方式,按理说应该能顺利进行,但在我们真正运行时却超级缓慢。这里我们忽视了几个重要的问题:
1.我们数据有40+个字段,而HBase导入测评字段数少。
2.HBase表没有预先创建分区,数据在插入过程中HBase会不停的执行split操作。
3.HBase的单个regionserver适合存储几个region?
网上有不少HBase数据导入调优的资料,海量数据导入最优的一种方式是将数据转化成HBase认知的HFile形式。该方式可以通过MapReduce输出HFile
job.setOutputFormatClass(HFileOutputFormat.class);
HFileOutputFormat.configureIncrementalLoad(job, new HTable(conf, hbase_table_name));
HFileOutputFormat.setOutputPath(job, new Path(outpath));
然后通过LoadIncrementalHFiles
Configuration HBASE_CONFIG = new Configuration();
conf = HBaseConfiguration.create(HBASE_CONFIG);
SchemaMetrics.configureGlobally(conf);
String[] params = new GenericOptionsParser(conf, args).getRemainingArgs();
if (params.length != 2) {
System.err.println("Usage: LoadHFileToHBase <hdfs_path> <hbase_table>");
System.exit(-1);
}
LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
HTable ht=new HTable(conf,params[1]);
ht.setAutoFlush(false);
loader.doBulkLoad(new Path(params[0]), ht);
load至HBase表中。需要注意的点有:HBase表需要预创建region,不然在转化HFile时只有一个reduce(有几个region就有几个reduce,如何预创建分区见下一节),导致转化超慢;如此也会想到,在做HFile转化时,HBase表在做其他导入操作或者说有split操作,会导致后续的load也会超级慢,所以我们在做MapReduce HFile的转化时,HBase表最好不要有任何写入操作。
那这种方式能顺利进行吗?我们预创建表region数1000和100分别做了测试,在load数据时,都会报超时的异样(很抱歉,异常信息未记录),真是痛不欲生,花了很长时间没有解决此问题。
随即,我们又回到原导入方式,预先创建了region测试,速度上有点点提升,效率上本人着实觉得不合理,一个map运行很长时间。分析一下,map按行获取数据,转化成put对象后,执行导入,各种调优参数也调了批量导入也试过了,就是不见速度上有提升。为啥?很可能是在连接HBase时耗时,该MapRecude采用内置连接HBase的方式即:
conf.set(TableOutputFormat.OUTPUT_TABLE, hbase_table_name);
job.setOutputFormatClass(TableOutputFormat.class);
接着,本人不采用内置连接方式
protected void setup(Context context) throws IOException, InterruptedException {
String table_name = context.getConfiguration().get("table_name").trim();
if (StringUtils.isNotBlank(table_name)) {
tablename = table_name;
ht = new HTable(context.getConfiguration(), tablename);
ht.setAutoFlush(false);
ht.setWriteBufferSize(5*1024*1024);
putlist = new ArrayList<Put>();
}
}
......
protected void cleanup(Context context) throws IOException, InterruptedException {
if (putlist.size() != 0){
ht.put(putlist);
putlist.clear();
}
ht.close();
}
立马map执行速度快了n倍,终于告了一段落。至于为何MapReduce内置连接HBase会慢,需查看源码,待研究。
常态化数据
由于常态化数据小,所以相应表采用普通的创建即可。HBase至HBase表操作采用org.apache.hadoop.hbase.mapreduce.CopyTable方式,HBase表至hive表采用MapReduce方式。
RowKey设计
使用HBase做存储,RowKey设计是最最关键的一部分。HBase查询数据方式有三种:
根据RowKey(高效)
根据RowKey区间(高效)
采用scan(转化成MapReduce低效,不满足实时性)
可见好的RowKey直接影响查询速率(此处未考虑secondary indexes)。
在数据导入过程中,需要预先创建region,也就是需要划分RowKey段。我们设计RowKey是数字型,对已有的初始化数据RowKey化分了1000份,经过测试,HBase会出现死节点情况,一个regionserver多少个region才合适呢?官方给出的答案是:
http://hbase.apache.org/book.html,2.5.2.6.1.how many regions per regions。
根据我们的实际情况,目前hadoop9个节点,4个regionserver。将1000份减少到100份,并根据数据量的大小,每个region设置成6G
public static boolean createTable(String tableName, String family, byte[][] splits) throws IOException {
HBaseAdmin admin = new HBaseAdmin(conf);
try {
if (admin.tableExists(tableName)) {
System.out.println("table already exists!");
} else {
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
tableDesc.addFamily(new HColumnDescriptor(family));
tableDesc.setMaxFileSize(new Long("6442450900"));
admin.createTable(tableDesc, splits);
return true;
}
return false;
} catch (TableExistsException e) {
return false;
}
}
public static byte[][] getHexSplits(String[] regions) {
int numRegions = regions.length;
byte[][] splits = new byte[numRegions - 1][];
for (int i = 0; i < numRegions - 1; i++) {
BigInteger key = new BigInteger(regions[i], 16);
byte[] b = String.format("%016x", key).getBytes();
splits[i] = b;
}
return splits;
}
应用总结
适合TB级别数据,将会增长到TB级别数据。
很高的写吞吐量,瞬间写入量大。
可通过rowkey访问数据,hbase rowkey访问数据最高效。
列可扩展。
结构化、半结构化数据。
无交叉表、连接表、多层索引、事务操作的数据模型。
遗留的问题
secondary indexesCCHADOOP-95 - hbase secondary indexes - OPEN ,0.94版本没有此功能,期待后续版本提供类似select * from table where anycell="XXX"的功能,目前国内有公司在应用层实现创建索引表,在应用层实现索引查询功能。
load HFile时超时的异样
表设计中,热数据表和增量冷数据表数据小,也采用了HBase存储。可通过关系型数据做中间存储替换,或者将3张表合并成一张大表替换(前提索引问题解决)。
分享到:
相关推荐
HBase AMWU-大数据一:hello HBase (HBase1.03伪单机版本安装,Windows7 JAVA远程调用)
### HBase概述 HBase是一种基于Hadoop框架的分布式、可扩展的大数据存储系统,它提供了类似Bigtable的功能,能够实现在Hadoop和HDFS之上构建高性能、高可靠性的列式存储数据库。作为一种NoSQL数据库,HBase适用于...
上机实操,熟悉指令操作Hbase和java代码操作Hbase 二、实验环境 Windows 10 VMware Workstation Pro虚拟机 Hadoop环境 Jdk1.8 三、实验内容 1:指令操作Hbase (1):start-all.sh,启动所有进程 (2):start-hbase.sh...
- 向test表中的row1行,cf1列族下的greet列中插入字符串'hello':`put 'test', 'row1', 'cf1:greet', 'hello'`。 每个列族可以包含多个列,列名由列族名和列限定符组成,中间使用冒号分隔。 6. 获取特定行的数据...
append.addColumn(Bytes.toBytes("cf3"), Bytes.toBytes("message"), Bytes.toBytes("Hello, ")); Result appendedResult = table.append(append); ``` 以上就是HBase Java API进行增加、修改和删除操作的基本用法...
例如,a:cf1:bar:***:7和a:cf1:foo:***:hello都遵循这种格式。 在物理模型方面,HBase的一张表由一个或多个Hregion组成,记录之间按照RowKey的字典序排列。Region按大小分割,每个表一开始只有一个region,随着数据...
【HBase 分布式数据库实验】是一份详细指导如何在实验环境中操作和管理HBase的教程,适合于学习大数据技术的人员。实验手册涵盖了HBase的基础知识、数据管理和集群管理等多个方面,旨在通过实践帮助读者深入理解...
Hive的HelloWorld程序 链接hbase,搜索字段输出
Apache Phoenix 是一个高性能的关系型数据库层,专门为Apache HBase设计,允许用户通过SQL查询和管理HBase中的数据。Phoenix利用JDBC驱动程序将SQL查询转换为HBase的原生操作,提高了查询性能,尤其适用于大数据分析...
HBASE 权威指南 ... “Hello! This is AWS. Whatever you are running, please turn it off!”). They were looking for an alternative. The Google Bigta‐ ble paper1 had just been published.
### Hello World半成品.pptx 知识点总结 #### 一、华为云数据中心与挖掘设计总体方案概览 **1.1 商业挑战与需求** - **商业挑战:** - 面对日益增长的数据量和业务复杂度,企业需要更高效地管理和利用数据资源,...
例如,如果公共类名为`HelloWorld`,那么源文件名也必须是`HelloWorld.java`。如果文件名与类名不符,编译器可能能够成功编译,但运行时会因为找不到正确的类定义而抛出`NoClassDefFoundError`。 ### 解决方法: ...
### 高级软件人才培训专家-Hadoop课程资料-1-第一章 - Hello大数据&分布式 #### 知识点概览 1. **数据的概念与价值** - 数据的基本定义及其在现代社会中的重要性。 - 数据如何影响现实生活的具体案例。 2. **...
Kafka测试Hello World示例 此使用开放源代码库进行声明式样式测试。 可以克隆和运行多种口味的。 运行测试之前,请确保启动 。 让我们学习自动测试Kafka应用程序的最简单,最有效的方法。 在以下情况下特别有用: ...
在类中,我们添加一个 HelloWorld 方法,用于处理请求和响应。 资源目录结构 在 Maven 项目中,我们需要创建一个正确的目录结构。我们需要创建一个 src/main/java 文件夹,用于存放代码,然后创建一个 test 文件夹...
`udf`函数用于自定义处理逻辑,这里注册了一个简单的将字符串前缀"hello"的方法。 3. Hive: - Hive是基于Hadoop的数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供SQL接口进行查询。 - 内部表和...
- **第一个HelloWorld程序** - 编写一个简单的WordCount程序,了解MapReduce的基本流程。 - **一个单表关联的例子** - 实现一个简单的数据处理任务,如两个表的关联操作。 #### 四、在Linux上安装Hive - **目的*...
环境安装与Hello-World DEMO 核心环境搭建 ---依赖[0] ---依赖[1] ---依赖[1] ---依赖[3] spark探索 本节均依赖[3]或[4]。 生态环境搭建 MySQL搭建 MySQL 8.0环境搭建 Hive与HBASE HBASE分布式环境搭建 Hive环境搭建...