Hbase
1. 数据存储
1.1 RDBMS:
-
Data is typed structured before stored
-
传统SQL
data location entity table record row query group by 、join -
大数据时代,如何做实时查询?
-
hadoop/HDFS:能存 没法进行实时查询,随机读写
-
NoSQL(NOT only SQL):HBase、Redis
1.2 Hbase在Hadoop生态圈中的位置
- HBase是Hadoop生态圈中的一个重要组成部分
- HBase是构建在HDFS纸上,也就是说HBase的数据可以存储在HDFS上面
- 可以通过MapReduce/Spark来处理Hbase中的数据
- HBase也提供了shell、API的方式进行数据的访问
1.3 行式VS列式
-
行式
-
按行存储
-
没有索引查询的时候需要耗费大量的IO
-
可以通过建立索引或者视图来提速
-
1,3zz,23
-
-
列式
- 压缩、并行处理
- 数据就是索引,大大降低IO
1.4 HBase特点
-
大:数据量大
-
面向列:列族(可以存放很多列),列族/列独立索引
-
稀疏:
id name age ... 1 3zz 0 2 4xx 0 3 5yy 0 -
数据类型单一:byte/string
-
无模式:每一行的数据所对应的列不一定相同,每行的列是可以动态添加的
3zz age/birthday/company 4xx company/province/city
-
数据多版本:比如company可以存放不同的版本的值
默认情况下版本号是自动分配的,是列的值插入时的时间戳
1.5 HBase VS MySQL
-
数据类型不同
-
数据操作:
- 关联查询:MapReduce/Spark/Phoenix
- get/put/scan...
-
存储模式
-
MySQL
id name age tel Address 1 a 11 123 ... 2 b 22 456 ... 3 c 33 789 ... -
在HBase中
basic_info: id name private_info: age tel address
-
-
transaction事务性:单行
-
数据量:HBase大
-
吞吐量:Million级别
HBase vs HDFS
- write pattern(写模式)
- read pattern(读模式)
- SQL
- data size(数据量)
HBase优势
- 成熟
- 高效
- 分布式
数据模型
-
rowkey
-
主键
-
字符串,按字典顺序存储,在HBase内部保存的是字节数组
-
-
列族:Column Family (CF)
-
是在创建表的时候就要指定的
-
列族是一系列列的集合
-
一个列族所有列有着相同的前缀
basic_info: id basic_info: name private_info: age private_info: tel private_info: address
-
-
列:Column / Qualifier
- 属于某一个列族
-
每条记录被划分到若干个CF中,每条记录对应一个rowkey,每个CF由一个或者多个Column构成
-
存储单元:Cell
- HBase中ROW和Column确定的一个存储单元
- 每个Cell都保存这同一份数据的多个版本
- 在写入数据时,时间戳可以由HBase自动赋值,也可以显示赋值
- 每个Cell中,不同版本的数据按照时间戳的倒序排列
{rowkey, column, version} ==> HBase 中的一个Cell
2. HBase安装
2.1 前置需要
- JDK(略过)
- ZooKeeper安装(brew)
- Hadoop安装(使用cdh版本,详细配置参照前面博客)
2.2HBase安装:
-
在.bash_profile中添加HBASE_HOME
-
在HBase的
conf
目录中修改两个文件-
在
hbase-env.sh
文件中# 1.修改java的路径 # The java implementation to use. Java 1.7+ required. # export JAVA_HOME=/usr/java/jdk1.6.0/ export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home # 注意 这里一定要是用1.8的版本! 上面使用java12是要出大问题的 # 2.修改zookeeper配置 # Tell HBase whether it should manage it's own instance of Zookeeper or not. export HBASE_MANAGES_ZK=false
-
在
hbase-site.xml
中配置<configuration> <!--hbase的数据存放地址(本机)--> <property> <name>hbase.rootdir</name> <value>hdfs://localhost:8020/hbase</value> </property> <!--分布式配置--> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <!--本机zookeeper地址--> <property> <name>hbase.zookeeper.quorum</name> <value>localhost:2181</value> </property> </configuration>
-
2.3 启动HBase
- 先启动hadoop目录下
sbin/start-dfs.sh
- 启动zookeeper
zKserver start
- 启动HBase目录下的
bin/start-hbase.sh
- 打开本机60010端口,有界面 则成功
2.4 HBase shell使用
- 在
bin
目录下输入hbase shell
即可进入shell脚本- 查看版本
version
- 查看服务器的状态
status
- 查看版本
3. HBase相关操作
3.1 DDL操作
- 创建、查询
# 创建
create 'member','member_id','address','info'
# 查询详细信息
desc 'member'
- 返回信息如下:
{NAME => 'address', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCOD
ING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICA
TION_SCOPE => '0'}
{NAME => 'info', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING
=> 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATIO
N_SCOPE => '0'}
{NAME => 'member_id', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENC
ODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLI
CATION_SCOPE => '0'}
- 也可以在图形化界面,即60010端口上查看,点击最上面的
Table Details
# 查看有哪些表
hbase(main):007:0> list
=> ["member"]
# 删除列族中的一列
hbase(main):008:0> alter 'member' ,'delete'=>'member_id'
1/1 regions updated.
Done.
- 此时在查看
member
表的结构
hbase(main):009:0> desc 'member'
COLUMN FAMILIES DESCRIPTION
{NAME => 'address', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCOD
ING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICA
TION_SCOPE => '0'}
{NAME => 'info', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING
=> 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATIO
N_SCOPE => '0'}
-
可以发现
member_id
已经被我们删掉了 -
删除表
# 先disable
hbase(main):011:0> disable 'member'
# 再drop
hbase(main):012:0> drop 'member'
# 此时再查看所有表
hbase(main):013:0> list
=> []
3.2 DML操作
-
为了方便,重新创建一张表
# 表名为member,列族为address、info create 'member','address','info'
-
创建/修改/删除表
# rowkey为行名(表名) cf为列族 column为列族中的一列 插入数据: put 表名,rowkey,cf:column,key
-
实际语句如下
put 'member','3z','info:age','23' put 'member','3z','info:birthday','1996-07-31'
-
查看member中数据
scan 'member' # 返回结果 ROW COLUMN+CELL 3z column=info:age, timestamp=12341241212, value=23 3z column=info:birthday, timestamp=12341241213, value=1996-07-31
-
获取某一行的数据
# 获取所有3z的数据 get 'member','3z' # 返回结果 COLUMN CELL info:age timestamp=1577955149575, value=23 info:birthday timestamp=1577955128970, value=1996-07-31
-
修改某一列
put 'member','3z','info:age','18' # 获取当前年龄 get 'member','3z','info:age' # 返回结果 COLUMN CELL info:age timestamp=1577955321212, value=18 # age已经被更新
-
删除某一列
delete 'member','3z','info:birthday' # 再查看3z的信息 get 'member','3z' # 返回结果 COLUMN CELL info:age timestamp=1577955321212, value=18 # 删除成功
-
统计一下几行
count 'member' # 返回结果 ==> 1
-
删除某个一整行
deleteall 'member','3z'
-
清空一张表
truncate 'member' # 会先自己disable 在truncate Truncating 'member' table (it may take a while): - Disabling table... - Truncating table... 0 row(s) in 3.4130 seconds
4. HBase API开发:Java/Scala
-
maven:pom.xml
:良好的网络支持package com.zth.bigdata.hbase; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.apache.hadoop.hbase.client.*; import org.apache.hadoop.hbase.util.Bytes; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.io.IOException; /** * Author: 3zZ. * Date: 2020/1/11 6:14 下午 */ public class HbaseApp { Connection connection = null; Table table = null; Admin admin = null; String tableName = "3z_hbase_java_api"; @Before public void setUp() { Configuration configuration = new Configuration(); configuration.set("hbase.rootdir", "hdfs://localhost:8020/hbase"); configuration.set("hbase.zookeeper.quorum", "localhost:2181"); try { connection = ConnectionFactory.createConnection(configuration); admin = connection.getAdmin(); Assert.assertNotNull(connection); Assert.assertNotNull(admin); } catch (IOException e) { e.printStackTrace(); } } @Test public void getConnection() { } @Test public void createTable() throws Exception { TableName table = TableName.valueOf(tableName); if (admin.tableExists(table)) { System.out.println(tableName + "已经存在"); } else { HTableDescriptor descriptor = new HTableDescriptor(table); descriptor.addFamily(new HColumnDescriptor("info")); descriptor.addFamily(new HColumnDescriptor("address")); admin.createTable(descriptor); System.out.println(tableName + "创建成功"); } } @Test public void queryTableInfos() throws Exception { HTableDescriptor[] tables = admin.listTables(); if (tables.length > 0) { for (HTableDescriptor table : tables) { System.out.println(table.getNameAsString()); HColumnDescriptor[] columnDescriptors = table.getColumnFamilies(); for (HColumnDescriptor hColumnDescriptor : columnDescriptors) { System.out.println("\t" + hColumnDescriptor.getNameAsString()); } } } } @Test public void testPut() throws Exception { table = connection.getTable(TableName.valueOf(tableName)); Put put = new Put(Bytes.toBytes("3z")); // 通过PUT设置要添加数据的CF、qualifier、value put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"), Bytes.toBytes("24")); put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("birthday"), Bytes.toBytes("731")); put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("company"), Bytes.toBytes("HIT")); put.addColumn(Bytes.toBytes("address"), Bytes.toBytes("country"), Bytes.toBytes("CN")); put.addColumn(Bytes.toBytes("address"), Bytes.toBytes("province"), Bytes.toBytes("BJ")); put.addColumn(Bytes.toBytes("address"), Bytes.toBytes("city"), Bytes.toBytes("BJ")); // 将数据put到hbase中去 table.put(put); } @Test public void testUpdate() throws Exception { table = connection.getTable(TableName.valueOf(tableName)); Put put = new Put(Bytes.toBytes("2z")); put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"), Bytes.toBytes("25")); table.put(put); } @Test public void testGet01() throws Exception { table = connection.getTable(TableName.valueOf(tableName)); Get get = new Get("3z".getBytes()); get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age")); Result result = table.get(get); printResult(result); } @Test public void testScan01() throws Exception{ table = connection.getTable(TableName.valueOf(tableName)); Scan scan = new Scan(); ResultScanner rs = table.getScanner(scan); for (Result result: rs){ printResult(result); } } public void printResult(Result result) { for (Cell cell : result.rawCells()) { System.out.println(Bytes.toString(result.getRow()) + "\t" + Bytes.toString(CellUtil.cloneFamily(cell)) + "\t" + Bytes.toString(CellUtil.cloneQualifier(cell)) + "\t" + Bytes.toString(CellUtil.cloneValue(cell)) + "\t" + cell.getTimestamp() ); } } @After public void tearDown() { try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
小结
-
Connection
-
Admin
-
HTableDescriptor
-
HcolumnDescriptor
-
创建表
-
删除表
-
添加记录:单挑、多条
-
修改记录
-
根据
RowKey
获取单挑记录 -
Scan
:空、起始、起始结尾、Get
-
Filter
:RowFilter
、PrefixFilter
、FilterList
-