目录
HBASE安装及使用
HBASE简介:
HBASE是一个数据库----可以提供数据的实时随机读写
HBASE相比于其他nosql数据库(mongodb、redis、cassendra、hazelcast)的特点:
HBASE安装:
HBASE是一个分布式系统
安装准备:
安装步骤:
1.安装zookeeper(前文已述)
2.安装hbase
3.启动hbase集群(hdfs,zk集群正常运行):
4.启动hbase的命令行客户端
HBASE表模型
hbase表模型的要点:
hbase命令行客户端操作
namespace(相当于RDBMS里的database,对table进行分组)
1.建表:
2.插入数据:
3.查询数据方式一:scan 扫描
4.查询数据方式二:get 单行数据
5.删除一个kv数据
6.删除整个表:
Hbase重要特性--排序特性(行键)
HBASE客户端API操作
1.DDL操作
2.DML操作
批量数据如何快速导入HBASE
HBASE的性能调优
MAPREDUCE分析HBASE中的数据
HBASE中的数据建索引
HBASE与mysql、oralce、db2、sqlserver等关系型数据库不同,它是一个NoSQL数据库(非关系型数据库)
Hbase的表模型与关系型数据库的表模型不同:
Hbase的表没有固定的字段定义;
Hbase的表中每行存储的都是一些key-value对
Hbase的表中有列族的划分,用户可以指定将哪些kv插入哪个列族
Hbase的表在物理存储上,是按照列族来分割的,不同列族的数据一定存储在不同的文件中
Hbase的表中的每一行都固定有一个行键,而且每一行的行键在表中不能重复
Hbase中的数据,包含行键,包含key,包含value,都是byte[ ]类型,hbase不负责为用户维护数据类型
HBASE对事务的支持很差
Hbase表模型示意图
Hbase的表数据存储在HDFS文件系统中
从而,hbase具备如下特性:
存储容量可以线性扩展
数据存储的安全性可靠性极高
其中有一个管理角色: HMaster(一般2台,一台active,一台backup)
其他的数据节点角色: HRegionServer(很多台,看数据容量)
首先,要有一个HDFS集群,并正常运行;regionserver应该跟hdfs中的datanode在一起
其次,还需要一个zookeeper集群,并正常运行
然后,安装HBASE
角色分配如下:
master: namenode datanode regionserver hmaster
hdp-01: datanode regionserver QuorumPeerMain
hdp-02: datanode regionserver QuorumPeerMain
hdp-03: datanode regionserver QuorumPeerMain
解压hbase安装包
修改hbase-env.sh
export JAVA_HOME=/usr/local/jdk
export HBASE_MANAGES_ZK=false
# Tell HBase whether it should manage it's own instance of Zookeeper or not(是否启用HBase自己的ZK,因为集群zk还要实现其他组件的高可用配置,故统一维护,如果集群出现多个zk集群,会出现端口占用等问题)
修改hbase-site.xml
hbase.rootdir
hdfs://master:9000/hbase
hbase.cluster.distributed
true
hbase.zookeeper.quorum
hdp-01:2181,hdp-02:2181,hdp-03:2181
修改 regionservers
hdp-01
hdp-02
hdp-03
环境变量配置
/root/apps/hbase-1.2.1/bin
复制到集群其他节点上.
scp -r /root/apps/hbase-1.2.1 hdp-01:/root/apps
bin/start-hbase.sh
启动完后,还可以在集群中找任意一台机器启动一个备用的master
bin/hbase-daemon.sh start master
新启的这个master会处于backup状态
外网web端口:(内部服务端口:16000)
http://master:16010/
bin/hbase shell
Hbase> list // 查看表
Hbase> status // 查看集群状态
Hbase> version // 查看集群版本
启动后可查看zookeeper中对HBASE的节点监控内容:
[zk: localhost:2181(CONNECTED) 13] ls /hbase
[backup-masters, draining, flush-table-proc, hbaseid, master, meta-region-server, namespace, online-snapshot, recovering-regions, region-in-transition, replication, rs, running, splitWAL, table, table-lock]
[zk: localhost:2181(CONNECTED) 13] ls /hbase/backup-masters
[hdp-02,16000,1586781803612]
[zk: localhost:2181(CONNECTED) 14] get /hbase/backup-masters/hdp-02
org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /hbase/backup-masters/hdp-02
hbase的表模型跟mysql之类的关系型数据库的表模型差别巨大
hbase的表模型中有:行的概念;但没有字段的概念
行中存的都是key-value对,每行中的key-value对中的key可以是各种各样,每行中的key-value对的数量也可以是各种各样
1、一个表,有表名
2、一个表可以分为多个列族(不同列族的数据会存储在不同文件中)
3、表中的每一行有一个“行键rowkey”,而且行键在表中不能重复
4、表中的每一对kv数据称作一个cell
5、hbase可以对数据存储多个历史版本(历史版本数量可配置)
6、整张表由于数据量过大,会被横向切分成若干个region(用rowkey范围标识),不同region的数据也存储在不同文件中
7、hbase会对插入的数据按顺序存储:
要点一:首先会按行键排序
要点二:同一行里面的kv会按列族排序,再按k排序
hbase的表中能存储什么数据类型
hbase中只支持byte[] hbase不负责为客户端维护数据类型
此处的byte[] 包括了:rowkey,key,value,列族名,表名
HBASE表的物理存储结构
hbase整体工作机制示意图
list_namespace #查看所有namespace 相当于show databases
default、hbase 2个内置namespace .
hbase:用来存放系统相关的一些元数据等,相当于mysql中的mysql数据库
建表时未指定namespace的表放在 default namespace中
create_namespace "test" #创建新的namespace{可添加一些说明}
create_namespace "test002", {"author"=>"CC11001100", "create_time"=>"2018-11-4 17:51:53"}
describe_namespace "test002"" #查看说明
alter_namespace "test002", {METHOD=>"set", "author"=>"ChenEr"} #修改说明
drop_namespace "test002" #删除namespace(必须为空)
create "test:user", "userInfo" #创建表时, "test:user" 表名前:指定namespace名
ist_namespace_tables "test" #查看namespace下都有哪些表
create 't_user_info','base_info','extra_info'
表名 列族名 列族名
hbase(main):011:0> put 't_user_info','001','base_info:username','zhangsan'
0 row(s) in 0.2420 seconds
hbase(main):017:0> scan 't_user_info'
ROW COLUMN+CELL
001 column=base_info:age, timestamp=1496567924507, value=18
001 column=base_info:sex, timestamp=1496567934669, value=female
hbase(main):020:0> get 't_user_info','001'
COLUMN CELL
base_info:age timestamp=1496568160192, value=19
base_info:sex timestamp=1496567934669, value=female
base_info:username timestamp=1496567889554, value=zhangsan
extra_info:career timestamp=1496567963992, value=it
4 row(s) in 0.0770 seconds
hbase(main):021:0> delete 't_user_info','001','base_info:sex'
0 row(s) in 0.0390 seconds
删除整行数据:
hbase(main):024:0> deleteall 't_user_info','001'
0 row(s) in 0.0090 seconds
hbase(main):028:0> disable 't_user_info'
0 row(s) in 2.3640 seconds
hbase(main):029:0> drop 't_user_info'
0 row(s) in 1.2950 seconds
插入到hbase中去的数据,hbase会自动排序存储:
排序规则: 首先看行键,然后看列族名,然后看列(key)名;按字典顺序
Hbase的这个特性跟查询效率有极大的关系
比如:一张用来存储用户信息的表,有名字,户籍,年龄,职业....等信息
然后,在业务系统中经常需要:
查询某个省的所有用户
经常需要查询某个省的指定姓的所有用户
思路:如果能将相同省的用户在hbase的存储文件中连续存储,并且能将相同省中相同姓的用户连续存储,那么,上述两个查询需求的效率就会提高!!!
做法:将查询条件拼到rowkey内
/**
* Hbase java 客户端API (DDL)
* 1、构建连接
* 2、从连接中取到一个表DDL操作工具admin
* 3、admin.createTable(表描述对象);
* 4、admin.disableTable(表名);
5、admin.deleteTable(表名);
6、admin.modifyTable(表名,表描述对象);
*/
public class HbaseClientDDL {
Connection conn = null;
/**
* 构建一个HBASE连接
*/
@Before
public void getConn() throws Exception{
// 构建一个HBaseConfiguration链接对象,默认加载hbase-site.xml
Configuration conf = HBaseConfiguration.create();
// 增加zookeeper配置
conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");
conn = ConnectionFactory.createConnection(conf);
}
/**
* 建表
*/
@Test
public void testCreateTable() throws Exception{
// 从链接中构造一个DDL操作器
Admin admin = conn.getAdmin();
// 创建表定义描述对象
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf("user_info"));
// 创建列族定义描述对象
HColumnDescriptor hColumnDescriptor1 = new HColumnDescriptor("base_info");
HColumnDescriptor hColumnDescriptor2 = new HColumnDescriptor("extra_info");
// 设置该列族中存放数据的最大版本数,默认为1
hColumnDescriptor1.setMaxVersions(3);
hColumnDescriptor2.setMaxVersions(3);
// 列族定义信息对象 放入 表定义对象中
hTableDescriptor.addFamily(hColumnDescriptor1);
hTableDescriptor.addFamily(hColumnDescriptor2);
// 使用ddl操作器对象 创建表
admin.createTable(hTableDescriptor);
// 关闭连接
admin.close();
conn.close();
}
/**
* 删除表
*/
@Test
public void testDropTable() throws Exception{
Admin admin = conn.getAdmin();
// 停用表 HBASE删除表,必须先停用
admin.disableTable(TableName.valueOf("user_info"));
// 删除表
admin.deleteTable(TableName.valueOf("user_info"));
admin.close();
conn.close();
}
/**
* 修改表
*/
@Test
public void testAlterTable() throws Exception{
Admin admin = conn.getAdmin();
// 获取 表描述对象
HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("user_info"));
System.out.println(tableDescriptor.toString());
// 创建新的列族定义对象
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("other_info");
// 设置该列族的布隆过滤器类型
hColumnDescriptor.setBloomFilterType(BloomType.ROWCOL);
// 列族定义添加到表定义对象中
tableDescriptor.addFamily(hColumnDescriptor);
// 修改过的表定义对象 提交给ddl操作器执行Alter操作
admin.modifyTable(TableName.valueOf("user_info"), tableDescriptor);
// 查看当前表的列族信息
for (HColumnDescriptor hCol : tableDescriptor.getColumnFamilies()) {
System.out.println(hCol.getNameAsString());
}
admin.close();
conn.close();
}
}
/**
* Hbase客户端API (DML 增删改查)
*/
public class HbaseClientDML {
Connection conn = null;
/**
* 构建一个HBASE连接
*/
@Before
public void getConn() throws Exception{
// 构建一个HBaseConfiguration链接对象,默认加载hbase-site.xml
Configuration conf = HBaseConfiguration.create();
// 增加zookeeper配置
conf.set("hbase.zookeeper.quorum", "hdp-01:2181,hdp-02:2181,hdp-03:2181");
conn = ConnectionFactory.createConnection(conf);
}
/**
* 增:put 改:put(同rowkey数据覆盖)
* @throws Exception
*/
@Test
public void testPut() throws Exception{
// 通过Hbase链接获取表描述对象,进行DML操作
Table table = conn.getTable(TableName.valueOf("user_info"));
// 构造一个Put对象类型,存放数据,最后插入表中.(一个put对象只能对应一个rowkey).
// HbaseJava客户端封装的api都比较底层,数据存入时,都是直接传入的二进制byte.
//Put put = new Put("001".getBytes());
// 以下使用了hbase工具库实现二进制,效果一致
Put put = new Put(Bytes.toBytes("001"));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("name"), Bytes.toBytes("张三"));
put.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("18"));
put.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("adrr"), Bytes.toBytes("北京"));
Put put2 = new Put(Bytes.toBytes("002"));
put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("name"), Bytes.toBytes("李四"));
put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("age"), Bytes.toBytes("28"));
put2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("sex"), Bytes.toBytes("male"));
put2.addColumn(Bytes.toBytes("extra_info"), Bytes.toBytes("adrr"), Bytes.toBytes("北京"));
ArrayList puts = new ArrayList<>();
puts.add(put);
puts.add(put2);
// 数据put:可以单个put,也可以put Put对象list
table.put(puts);
table.close();
conn.close();
}
/**
* 删
* @throws Exception
*/
@Test
public void testDelete() throws Exception{
// 通过Hbase链接获取表描述对象,进行DML操作
Table table = conn.getTable(TableName.valueOf("user_info"));
// 创建Delete对象,封装要删除的数据 (用rowkey识别)
Delete delete = new Delete(Bytes.toBytes("001"));
// Delete对象不增加其他数据列,则删除整个数据,若设置其他列,则删除该列kv
Delete delete2 = new Delete(Bytes.toBytes("002"));
delete2.addColumn(Bytes.toBytes("base_info"), Bytes.toBytes("sex"));
ArrayList deletes = new ArrayList<>();
deletes.add(delete);
deletes.add(delete2);
table.delete(deletes);
table.close();
conn.close();
}
/**
* 查询
* @throws Exception
*/
@Test
public void testGet() throws Exception{
// 通过Hbase链接获取表描述对象,进行DML操作
Table table = conn.getTable(TableName.valueOf("user_info"));
Get get = new Get(Bytes.toBytes("002"));
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes("base_info"), Bytes.toBytes("name"));
System.out.println(new String(value));
byte[] row = result.getRow();
System.out.println(new String(row));
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell cell = cellScanner.current();
byte[] rowArray = cell.getRowArray();// 行键字节数组
byte[] familyArray = cell.getFamilyArray(); // 列族字节数组
byte[] qualifierArray = cell.getQualifierArray(); // 列名字节数组
byte[] valueArray = cell.getValueArray(); // value字节数组
String rowkey = new String(rowArray,cell.getRowOffset(),cell.getRowLength());
String familykey = new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength());
String qualifierkey = new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength());
String valueval = new String(valueArray,cell.getValueOffset(),cell.getValueLength());
System.out.println("rowkey:"+rowkey+","+"familykey:"+familykey+","+"qualifierkey:"+qualifierkey+","+"valueval:"+valueval);
}
}
/**
* 按rowkey范围查询数据
* @throws Exception
*/
@Test
public void getScan() throws Exception{
Table table = conn.getTable(TableName.valueOf("user_info"));
Scan scan = new Scan(Bytes.toBytes("000"),Bytes.toBytes("100"));
ResultScanner scanner = table.getScanner(scan);
Iterator iterator = scanner.iterator();
while(iterator.hasNext()){
Result res = iterator.next();
while(res.advance()){
Cell cell = res.current();
byte[] rowArray = cell.getRowArray();// 行键字节数组
byte[] familyArray = cell.getFamilyArray(); // 列族字节数组
byte[] qualifierArray = cell.getQualifierArray(); // 列名字节数组
byte[] valueArray = cell.getValueArray(); // value字节数组
String rowkey = new String(rowArray,cell.getRowOffset(),cell.getRowLength());
String familykey = new String(familyArray,cell.getFamilyOffset(),cell.getFamilyLength());
String qualifierkey = new String(qualifierArray,cell.getQualifierOffset(),cell.getQualifierLength());
String valueval = new String(valueArray,cell.getValueOffset(),cell.getValueLength());
System.out.println("rowkey:"+rowkey+","+"familykey:"+familykey+","+"qualifierkey:"+qualifierkey+","+"valueval:"+valueval);
}
}
}
}
(以下内容属于Hbase高级,很重要但暂时没有相关资料待补充...)
bulkloader
HBASE的过滤查询
二级索引创建
自己建(协处理器)
Solr(可以直接跟HBASE整合做全文检索)
elastic search(也可以跟HBASE整合做二级索引)
布隆过滤器思想示意图