JAVA 开发 HBase 常用手册必备
Posted 每日运维
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA 开发 HBase 常用手册必备相关的知识,希望对你有一定的参考价值。
做java开发,日常工作中可能会做个pass平台了,存点监控数据什么的,搞搞聚合啥的,简单的方式都会用到hbase,难别是现在大数据概念泛滥,懂点hbase更是必不可少。只要不是做宽表的研发,仅仅使用下增删改查就足够了。首先得了解下hbase的表结构,和关系型数据库有什么区别,了解hbase的java API,能够简单运维下OK了。
HBase的表结构
列族是列的集合,一个列族中包含多个列
row key base_info ext_info TimeStamp
特点:
1) RowKey: 行键,可理解成mysql中的主键列,每一行的ID,这个字段是自动创建的,建表时不需要指定
2) Column: 列,可理解成MySQL列。
3) ColumnFamily: 列族, HBase引入的概念:
将多个列聚合成一个列族。可以理解成MySQL的垂直分区(将一张宽表,切分成几张不那么宽的表)。此机制引入的原因,是因为HBase相信,查询可能并不需要将一整行的所有列数据全部返回。对应到文件存储结构(不同的ColumnFamily会写入不同的文件)。
4) TimeStamp:在每次跟新数据时,用以标识一行数据的不同版本(事实上,TimeStamp是与列绑定的。)
小结:
1.建表时,定义的是表名和列族(字段的集合),而不是具体字段
2.列族中可以包含任意个字段,字段名不需要预定义,每一行中同一列族中的字段也可以不一致
3.多维结构,关系数据库的表是二维的,通过指行、列定位一个数据,HBase中需要通过 行健、列族名、字段名、版本号才能定位到具体数据
4.插入数据时,一次插入一个字段的数据,不是像关系数据库那样一次插入多个字段
HBase使用了LSM树实现了MAP,简单说来,就是将插入/修改操作缓存在内存中,当内存中积累足够的数据后,再以块的形式刷入到磁盘上。
单机安装:依赖zookeeper和jdk
在官网http://apache.claz.org/hbase/下载hbase-1.2.6-bin.tar.gz
tar zxvf hbase-1.2.6-bin.tar.gz
mv hbase-1.2.6 hbase
mkdir -p hbase/data
chown -R hadoop.hadoop hbase
添加环境变量:
export PATH=$PATH:/export/Shell/hbase/bin
source /etc/profile
配置/conf/hbase-env.sh
export JAVA_HOME=/usr/java/jdk1.7.0_65 #配置本机的java安装根目录
export HBASE_MANAGES_ZK=true #配置由hbase自己管理zookeeper,不需要单独的zookeeper。
配置/conf/hbase-site.xml
<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///hbase/data</value>
</property>
</configuration>
启动
start-hbase.sh
shell:
./hbase shell
建表时要指定的是:表名、列族
1.建表语句
create 'user_info', 'base_info', 'ext_info'
意思是新建一个表,名称是user_info,包含两个列族base_info和ext_info
2.显示hbase中的表 list
3.查看表结构describe 'user_info'
4.插入:
put 'user_info', 'row1', 'base_info:name', 'a'
向user_info表中行健为row1的base_info列族中添加一项数据 name 值为a
5.查看指定列族的消息
get 'user_info','rk0001','info'
查看指定列族 指定字段的消息
get 'user_info','rk0001','info:age'
查看一段时间里的记录 通过时间戳范围查找
get 'user_info','rk0001',{COLUMN=>'info',VERSIONS=>3,TIMERANGE=>[1477654000000],[1477654111111]}
6.扫描表 scan 'user_info' 或者 scan "table_name" ,{LIMIT=>10}
查询列族为info,查询指定的rowkey范围
scan 'user_info',{COLUMN=>'info',STARTROW=>'rk0001',ENDROW=>'rk0003'}
7.删除表之前必须先禁用
disable 'user_info'
drop 'user_info'
8.清空表中数据 truncate ‘user_info'
9.向表中添加列簇 alter 'user_info','test'
删除列簇 alter 'user_info','delete'=>'test'
10.删除指定字段的值 delete 'user_info','rk0001','info:age'
通过时间戳删除指定版本 delete 'user_info','rk0001','info:age',1477654302911
11.查看表中的记录总数 count 'table_name'
12.分配权限
READ('R'), WRITE('W'), EXEC('X'), CREATE('C'), ADMIN('A') #
给用户‘test'分配对表t1有读写的权限
grant 'test','RW','t1'
13.查看表t1的权限列表 user_permission 't1'
14.收回test用户在表t1上的权限 revoke 'test','t1'
15.查看表是否存在 exists 'table_name'
插入数据PUT
HBase数据插入使用Put对象,Put对象在进行数据插入时,首先会想Hbase集群发送一个RPC请求,得到响应后将Put类中的数据通过序列化的方式传给HBase集群,集群节点拿到数据后进行添加功能。
1.检查表
HTable table=new HTable(conf,TableName.valueOf(tableName));
HBaseAdmin admin=new HBaseAdmin(conf);
//判断表是否存在,如果不存在进行创建
if(!admin.tableExists(Bytes.toBytes(tableName)))
{
HTableDescriptor tableDescriptor=new HTableDescriptor(Bytes.toBytes(tableName));
HColumnDescriptor columnDescriptor=new HColumnDescriptor(Bytes.toBytes(family));
tableDescriptor.addFamily(columnDescriptor);
admin.createTable(tableDescriptor);
}
table.setAutoFlush(true); //设置为自动提交
2.单行插入即每一次插入一行数据
Put put=new Put(Bytes.toBytes(rowKey));
put.add(Bytes.toBytes(family),Bytes.toBytes(column),Bytes.toBytes(value));
table.put(put);
table.close();
3.批量插入:put(List<Put> list)
int length=rowKeys.length;
List<Put> putList=new ArrayList<>();
for(int i=0;i<length;i++)
{
Put put=new Put(Bytes.toBytes(rowKeys[i]));
put.add(Bytes.toBytes(families[i]),Bytes.toBytes(columns[i]),Bytes.toBytes(values[i]));
putList.add(put);
}
table.put(putList);
table.close();
4.检查并写入:checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value, Put put)
该方法提供了一种原子性操作,即该操作如果失败,则操作中的所有更改都失效。该函数在多个客户端对同一个数据进行修改时将会提供较高的效率。
HTable table=new HTable(conf, TableName.valueOf(tableName));
Put put=new Put(Bytes.toBytes(row));
put.addColumn(Bytes.toBytes(family),Bytes.toBytes(column),Bytes.toBytes(value));
table.checkAndPut(Bytes.toBytes(row),Bytes.toBytes(family),Bytes.toBytes(column),null, put);
table.flushCommits();
5.缓存块操作
当所有该缓存区已经满溢的时候将缓存区中的数据通过一次RPC操作,一次提交到HBase集群中去。所以缓存块在进行大量put请求,且数据量较小时将会明显提高效率。
//创建表连接
HTable table=new HTable(conf,TableName.valueOf(tableName));
//将数据自动提交功能关闭
table.setAutoFlush(false);
//设置数据缓存区域
table.setWriteBufferSize(64*1024*1024);
//然后开始写入数据
int length=rows.length;
for(int i=0;i<length;i++)
{
Put put=new Put(Bytes.toBytes(rows[i]));
put.addColumn(Bytes.toBytes(families[i]),Bytes.toBytes(columns[i]),Bytes.toBytes(values[i]));
table.put(put);
}
//刷新缓存区
table.flushCommits();
//关闭表连接
table.close();
查询分为单条随机查询和批量查询。单条查询通过 Row Key 在Table 中查询某一行的数据,HTable 提供了get 方法完成单条查询。批量查询通过制定一段 Row Key 的范围来查询,HTable 提供了 getScanner 方法完成批量查询。
public Get(byte [] row)
public Get(byte [] row,RowLock rowLock)
Row Lock 为了保证读写的原子性,可以传递一个已经存在 Row Lock,否则 HBase 会自动生成一个新的 Row Lock。
setStartRow:指定开始的行。如果不调用,从表头开始。
setStopRow:指定结束的行(不含此行)。
setBatch:指定最多返回的 Cell 数目。防止一行中有过多的数据,导致 OOM 错误。
getRow:返回 Row Key。
raw:返回所有的 KeyValue 数组。
getValue:按照 Column 来获取 Cell 的值。
ResultScanner 是 Result 的一个容器,每次调用ResultScanner 的next 方法会返回Result。
6.查询所有行
HTableInterface table = null;
List<Result> rsList = new ArrayList<Result>();
table = conn.getTable(tableName);
Scan scan = new Scan();
ResultScanner scanner = table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
Result rs = null;
while (iterator.hasNext()) {
rs = (Result) iterator.next();
rsList.add(rs);
}
7.查询范围
HTableInterface table = null;
List<Result> rsList = new ArrayList<Result>();
table = conn.getTable(tableName);
Scan scan = new Scan();
ResultScanner scanner = table.getScanner(scan);
Iterator<Result> iterator = scanner.iterator();
Result rs = null;
while (iterator.hasNext()) {
rs = (Result) iterator.next();
rsList.add(rs);
}
切分表--HBaseAdmin 提供 split 方法将 table 进行切分。
public void split(final String tableNameOrRegionName)
如果提供的是 tableName,会将 table 所有 Region 进行切分;如果提供的是 RegionName,只会切分这个Region。Split 是一个异步操作,因此它并不能确切控制 Region 的个数。
8.切分
HTable hTable = new HTable(cfg,tableName);
int oldsize = 0;
long time = System.currentTimeMillis();
while(true){
int size = hTable.getRegionsInfo().size();
logger.info("the region number="+size);
if(size>=number) break;
if(size !=oldsize){
hAdmin.split(hTable.getTableName());
oldsize = size;
}else if(System.currentTimeMillis()-time>timeout){
break;
}
以上是关于JAVA 开发 HBase 常用手册必备的主要内容,如果未能解决你的问题,请参考以下文章