搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > 每日运维 > JAVA 开发 HBase 常用手册必备

JAVA 开发 HBase 常用手册必备

每日运维 2017-12-01

做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 常用手册必备》的版权归原作者「每日运维」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注每日运维微信公众号

每日运维微信公众号:yongjie_liu2015

每日运维

手机扫描上方二维码即可关注每日运维微信公众号

每日运维最新文章

精品公众号随机推荐