HBase
Hbase
概述
概述
- 一种分布式、可扩展、支持海量数据存储的NoSQL数据库
基本结构
Master
- Table:create,delete,alter
- RegionServer:分配Regions到每个RegionServer,监控RegionServer状态
RegionServer
- Data:get,put,delete
- Region:splitRegion,compactRegion
数据模型
- Name Space
- 类似于database
- 自带命名空间
- hbase:HBase内置的表
- default:用户默认使用的命名空间
- Table
- 类似于表
- 字段可以动态、按需指定
- Row
- 每行数据都由一个RowKey和多个Column(列)组成
- 按RowKey的字典顺序存储,原则上只能根据RowKey进行检索查询数据
- Column
- 由Column Family(列族)和Column Qualifier(列限定符)进行限定
- Time Stamp
- 用于标识数据的不同版本
- Cell
- 由
{rowkey, column Family:column Qualifier, time Stamp}
唯一确定的单元
- 由
安装
环境变量
1
2
3
4# vim /etc/profile.d/env.sh
# HBASE_HOME
export HBASE_HOME=/hbase
export PATH=$PATH:$HBASE_HOME/bin修改hbase-env.sh
1
2
3
4# 是否用内置Zookeeper
export HBASE_MANAGES_ZK=false
# 打开下面的注释行
export HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP="true"修改hbase-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<configuration>
<property>
<name>hbase.rootdir</name>
<!-- 单点集群 -->
<value>hdfs://bigdata1:8020/hbase</value>
<!-- 高可用,来自于hdfs-site.xml的配置dfs.nameservices -->
<value>hdfs://bigdata:8020/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata1,bigdata2,bigdata3</value>
</property>
</configuration>配置regionservers
1
2
3bigdata1
bigdata2
bigdata3同步文件
启动
单点启动
1
2
3
4hbase-daemon.sh start master
hbase-daemon.sh stop master
hbase-daemon.sh start regionserver
hbase-daemon.sh stop regionserver如果集群之间的节点时间不同步,会导致regionserver无法启动,抛出ClockOutOfSyncException异常
1
2
3
4
5
6<!-- 设置更大值 -->
<property>
<name>hbase.master.maxclockskew</name>
<value>180000</value>
<description>Time difference of regionserver from master</description>
</property>
集群启动
1
2start-hbase.sh
stop-hbase.sh
高可用(可用)
在conf目录下创建backup-masters文件,并配置高可用HMaster节点
1
2
3bigdata1
bigdata2
bigdata3同步文件
Shell操作
基本操作
1 |
|
namespcae操作
查看
1
2
3
4
5# 查看当前Hbase中有哪些namespace
list_namespace
# 查看namespace
describe_namespace "namespace名"增加
1
2
3# 创建namespace
create_namespace "namespace名"
create_namespace "namespace名", {"属性key"=>"属性value", "属性key"=>"属性value"}修改
1
2
3# 修改namespace的信息(添加或者修改属性)
alter_namespace "namespace名", {METHOD => 'set', '属性key' => '属性value'}
# 可以添加或者修改属性删除
1
2
3
4
5# 删除属性
alter_namespace 'namespace名', {METHOD => 'unset', NAME => '属性key'}
# 删除namespace,要删除的namespace必须是空的,其下没有表
drop_namespace "namespace名"
表操作
查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 查看当前数据库中有哪些表
list
# 扫描查看表数据
scan 'table名'
scan 'table名',{STARTROW => 'rowkey值'}
# [), 若想取1到2之间的数据:start=1,stop=2!
scan 'table名',{STARTROW => 'rowkey值', STOPROW => 'rowkey值'}
# 查看表结构
desc 'namespace名:table名'
# 查看“指定行”或“指定列族:列”的数据
get 'namespace名:table名','rowkey值'
get 'namespace名:table名','rowkey值','列族名:列名'
# 统计表数据行数
count 'namespace名:table名'增加
1
2
3
4
5
6
7
8
9
10
11# 创建表,不指定namespace则使用默认namespace
create 'namespace名:table名',{NAME => '列族名1', VERSION => '要保留的版本数'}
create 'namespace名:table名',{NAME => '列族名1'},{NAME => '列族名2'}
create 'namespace名:table名','列族名1','列族名2'
# 插入数据到表
put 'namespace名:table名','rowkey值','列族名:列名','值'
put 'student','1001','info:age','18'
put 'student','1002','info:name','Janna'
put 'student','1002','info:sex','female'
put 'student','1002','info:age','20'修改
1
2
3
4
5
6
7# 更新指定字段的数据
put 'namespace名:table名','rowkey值','列族名:列名','值'
put 'student','1001','info:age','100'
# 将info列族中的数据存放3个版本:
alter 'namespace名:table名',{NAME =>'列族名',VERSIONS => '要保留的版本数'}
get 'student','1001',{COLUMN => 'info:name', VERSIONS => 3}删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 删除某列族名
alter 'namespace名:table名', 'delete' => '列族名'
# 删除某rowkey的全部数据
deleteall 'namespace名:table名','rowkey值'
deleteall 'namespace名:table名','rowkey值','列族名:列名'
# 删除某rowkey的某一列数据,若不指定时间戳则删除最新的一条数据
delete 'namespace名:table名','rowkey值','列族名:列名'
delete 'namespace名:table名','rowkey值','列族名:列名','时间戳'
# 清空表数据
truncate 'namespace名:table名'
# 提示:清空表的操作顺序为先disable,然后再truncate。
# 删除表,首先需要先让该表为disable状态
disable 'namespace名:table名'
# 然后才能drop这个表
drop 'namespace名:table名'
# 如果直接drop表,会报错:ERROR: Table student is enabled. Disable it first.
原理
RegionServer架构
1 |
|
- StoreFile
- 保存实际数据的物理文件,StoreFile以Hfile的形式存储在HDFS上。每个Store会有一个或多个StoreFile(HFile),数据在每个StoreFile中都是有序的
- MemStore
- 写缓存,由于HFile中的数据要求是有序的,所以数据是先存储在MemStore中,排好序后,等到达刷写时机才会刷写到HFile,每次刷写都会形成一个新的HFile
- WAL
- 由于数据要经MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入MemStore中
- BlockCache
- 读缓存,每次查询出的数据会缓存在BlockCache中,方便下次查询
- 一个RegionServer可服务于多个Region,有多个Store,一个WAL和一个BlockCache
- 一个Store对应一个列族,包含MemStore和StoreFile
写流程
- Client访问zookeeper,获取
hbase:meta
表位于哪个Region Server - 访问对应的Region Server获取
hbase:meta
表,根据读请求的namespace:table/rowkey
查询出目标数据位于哪个Region Server中的哪个Region中,将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问 - 与目标Region Server进行通讯
- 将数据顺序写入(追加)到WAL
- 将数据写入对应的MemStore,数据会在MemStore进行排序
- 向客户端发送ack
- 等达到MemStore的刷写时机后,将数据刷写到HFile
MemStore Flush
每次刷写都会产生新文件
手动刷写命令
1
flush 'table名'
刷写机制
当某个memstore的大小达到以下值时,所在region的所有memstore都会刷写
hbase.hregion.memstore.flush.size
:默认128M
当memstore的大小达到以下值相乘时,阻止继续往该memstore写数据,直到大小小于以下值相乘的值以下
hbase.hregion.memstore.flush.size
:默认128Mhbase.hregion.memstore.block.multiplier
:默认4
当region server中memstore的总大小达到以下值相乘时,region会按照其所有memstore的大小顺序(由大到小)依次进行刷写,直到region server中所有memstore的总大小减小到上述值以下
java_heapsize
hbase.regionserver.global.memstore.size
:默认0.4hbase.regionserver.global.memstore.size.lower.limit
:默认0.95
当region server中memstore的总大小达到以下值时,阻止继续往所有的memstore写数据
java_heapsize
hbase.regionserver.global.memstore.size
:默认0.4
到达自动刷写的时间触发memstore flush。由以下属性进行配置
hbase.regionserver.optionalcacheflushinterval
:默认1小时
读流程
- Client访问zookeeper,获取
hbase:meta
表位于哪个Region Server - 访问对应的Region Server,获取
hbase:meta
表,根据读请求的namespace:table/rowkey查询出目标数据位于哪个Region Server中的哪个Region中,并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问 - 与目标Region Server进行通讯
- 分别在MemStore和Store File(HFile)中查询目标数据,并将查到的所有数据进行合并
- 所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)
- 使用时间戳范围,RowKey范围,布隆过滤器
- 将查询到的新的数据块(Block,HFile数据存储单元,默认大小为64KB)缓存到Block Cache
- 将合并后的最终结果返回给客户端
StoreFile Compaction
- Minor Compaction
- 将临近的若干个较小的HFile合并成一个较大的HFile,并清理部分过期和删除的数据
- 每次Flush后尝试
- Major Compaction
- 将一个Store下的所有的HFile合并成一个大HFile,并清理所有过期和删除的数据
- 周期性
Region Split
- 默认情况,每个Table起初只有一个Region
切分时机
- Hbase 0.94-:当1个region中的某个Store下所有StoreFile的总大小超过
hbase.hregion.max.filesize
:默认10G - Hbase 0.94+:当1个region中的某个Store下所有StoreFile的总大小超过
Min(initialSize*R^3, hbase.hregion.max.filesize)
- initialSize:默认
2 * hbase.hregion.memstore.flush.size
- R:当前Region Server中属于该Table的Region个数
- 具体切分策略
- 第一次split:1^3 * 256 = 256MB
- 第二次split:2^3 * 256 = 2048MB
- 第三次split:3^3 * 256 = 6912MB
- 第四次split:4^3 * 256 = 16384MB > 10GB,因此取较小的值10GB
- 第n次split:10GB
- initialSize:默认
- Hbase 2.0:若当前RegionServer上该表只有一个Region,按
2*hbase.hregion.memstore.flush.size
分裂,否则按hbase.hregion.max.filesize
分裂- 第一次按256M拆分,后续按10G拆分
API
环境
1 |
|
DDL
1 |
|
DML
1 |
|
优化
预分区
每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护
手动设定预分区
1
2
3create 'NameSpace名:Table名','Family名',SPLITS => ['预分区范围','预分区范围','预分区范围','预分区范围']
# (-∞,1000], (1000,2000], (2000,3000], (3000,4000], (4000,+∞)
create 'staff1','info',SPLITS => ['1000','2000','3000','4000']生成16进制序列预分区
1
2
3create 'NameSpace名:Table名','Family名',{NUMREGIONS => 分区数, SPLITALGO => 'HexStringSplit'}
# 00000000 ~ ffffffff 分成15份
create 'staff2','info',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}按照文件中设置的规则预分区
1
2
3
4
5
6
7
8
9create 'NameSpace名:Table名','Family名',SPLITS_FILE => '文件名'
# 创建splits.txt文件内容如下
aaaa
bbbb
cccc
dddd
# 执行
# (-∞,aaaa], (aaaa,bbbb], (bbbb,cccc], (cccc,dddd], (dddd,+∞)
create 'staff3','info',SPLITS_FILE => 'splits.txt'使用JavaAPI创建预分区
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 自定义算法,产生一系列Hash散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
// 创建HbaseAdmin实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
// 创建HTableDescriptor实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
// 通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表
hAdmin.createTable(tableDesc, splitKeys);
// 预分区:['1000','2000','3000','4000']
byte[][] splitKeys = new byte[4][];
splitKeys[0] = Bytes.toBytes(1000);
splitKeys[1] = Bytes.toBytes(2000);
splitKeys[2] = Bytes.toBytes(3000);
splitKeys[3] = Bytes.toBytes(4000);
admin.createTable(tableDescriptorBuilder.build(), splitKeys);
RowKey设计
原则:唯一性、散列性、长度
案例
场景:大量的运营商的通话数据
1
1388888888(主叫) 13999999999(被叫) 2021-05-14 12:12:12 360 ......
业务:查询某个用户 某天 某月 某年 的通话记录
预分区:预计规划50个分区
1
2
3
4(-∞ ~ 00]
(00 ~ 01]
(01 ~ 02]
.......分析
若将某个用户某天的数据存到一个分区中. 查某天的数据只需要扫描一个分区,若将某个用户某月的数据存到一个分区中. 查某天某月的数据只需要扫描一个分区
1
2# 若1388888888_2021-05 % 分区数 = 01
rowkey:01_1388888888_2021-05-14 12:12:12
验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36# 查询 1388888888 用户 2020年08月的通话记录
# 先计算分区号
1388888888_2020-08 % 50 = 04
# rowkey
04_1388888888_2020-08-........
# scan
scan "teldata" ,{STARTROW=> '04_1388888888_2020-08' STOPROW=> '04_1388888888_2020-08|'}
# 查询 1388888888 用户 2020年08月08日的通话记录
# 先计算分区号
1388888888_2020-08 % 50 = 04
# rowkey
04_1388888888_2020-08-08........
# scan
scan "teldata" ,{STARTROW=> '04_1388888888_2020-08-08' STOPROW=> '04_1388888888_2020-08-08|'}
# 查询 1388888888 用户 2020年08月 和 09月的通话记录
# 先计算分区号
1388888888_2020-08 % 50 = 04
1388888888_2020-09 % 50 = 06
# rowkey
04_1388888888_2020-08-........
06_1388888888_2020-09-........
# scan
scan "teldata" ,{STARTROW=> '04_1388888888_2020-08' STOPROW=> '04_1388888888_2020-08|'}
scan "teldata" ,{STARTROW=> '06_1388888888_2020-09' STOPROW=> '06_1388888888_2020-09|'}
# 查询 1388888888 用户 2020年08月09日 和 10日的通话记录
# 先计算分区号
1388888888_2020-08 % 50 = 04
# rowkey
04_1388888888_2020-08-09........
04_1388888888_2020-08-09........
04_1388888888_2020-08-10........
# scan
scan "teldata" ,{STARTROW=> '04_1388888888_2020-08-09' STOPROW=> '04_1388888888_2020-08-10|'}
基础优化
- Zookeeper会话超时时间
- hbase-site.xml:
zookeeper.session.timeout
- 默认90000毫秒(90s)。当某个RegionServer挂掉,90s之后Master才能察觉到。可适当减小此值,以加快Master响应,可调整至60000毫秒
- hbase-site.xml:
- 设置RPC监听数量
- hbase-site.xml:
hbase.regionserver.handler.count
- 默认30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值
- hbase-site.xml:
- 手动控制Major Compaction
- hbase-site.xml:
hbase.hregion.majorcompaction
- 默认604800000秒(7天), Major Compaction的周期,若关闭自动Major Compaction,可将其设为0
- hbase-site.xml:
- 优化HStore文件大小
- hbase-site.xml:
hbase.hregion.max.filesize
- 默认10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile
- hbase-site.xml:
- 优化HBase客户端缓存
- hbase-site.xml:
hbase.client.write.buffer
- 默认2097152bytes(2M)用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的
- hbase-site.xml:
- 指定scan.next扫描HBase所获取的行数
- hbase-site.xml:
hbase.client.scanner.caching
- 用于指定scan.next方法获取的默认行数,值越大,消耗内存越大
- hbase-site.xml:
- BlockCache占用RegionServer堆内存的比例
- hbase-site.xml:
hfile.block.cache.size
- 默认0.4,读请求比较多的情况下,可适当调大
- hbase-site.xml:
- MemStore占用RegionServer堆内存的比例
- hbase-site.xml:
hbase.regionserver.global.memstore.size
- 默认0.4,写请求较多的情况下,可适当调大
- hbase-site.xml:
整合
Phoenix
概述
- 是HBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据
- 特点
- 容易集成:如Spark,Hive,Pig,Flume和Map Reduce
- 操作简单:DML命令以及通过DDL命令创建和操作表和版本化增量更改
- 支持HBase二级索引创建
- 在phoenix中,schema名,表名,字段名等会自动转换为大写,若要小写,使用双引号,如”student”
安装
解压tar包,复制server包并拷贝到各个节点的hbase/lib
配置环境变量
1
2
3
4# PHOENIX_HOME
export PHOENIX_HOME=/phoenix
export PHOENIX_CLASSPATH=$PHOENIX_HOME
export PATH=$PATH:$PHOENIX_HOME/bin重启HBase
连接Phoenix
1
2
3
4
5
6
7
8
9
10
11# 厚客户端
# 默认找本机的zookeeper
sqlline.py
sqlline.py bigdata1,bigdata2,bigdata3
sqlline.py bigdata1,bigdata2,bigdata3:2181
python3 /phoenix/bin/sqlline.py bigdata1,bigdata2,bigdata3
# 薄客户端
# 默认找本机的zookeeper
queryserver.py start
sqlline-thin.py
sqlline-thin.py bigdata1:8765
Shell
schema
1
2
3
4
5<!--默认情况下,在phoenix中不能直接创建schema。需要将如下的参数添加到Hbase中conf目录下的hbase-site.xml 和 phoenix中bin目录下的 hbase-site.xml中-->
<property>
<name>phoenix.schema.isNamespaceMappingEnabled</name>
<value>true</value>
</property>1
2
3
4
5
6
7# 创建schema(库)
create schema if not exists mydb;
# 在phoenix中,schema名,表名,字段名等会自动转换为大写,若要小写,使用双引号,如"student"
create schema if not exists "mydb3";
# 删除schema
drop schema if exists "mydb3";表
1
2
3
4
5
6# 创建表,必须指定主键对应RowKey
CREATE TABLE IF NOT EXISTS student(
id VARCHAR primary key,
name VARCHAR,
addr VARCHAR
);数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 插入(修改)数据
upsert into student (id, name, addr) values('1001','zhangsan','beijing');
upsert into student (id, name, addr) values('1002','lisi','shanghai');
upsert into student (id, name, addr) values('1002','lixiaosi','shanghai');
upsert into student (id, name, addr);
# 会添加空字段,使插入合法
values('1003','wangwu','shanghai');
upsert into student (id, name, addr) values('1004',null,null);
# 查询数据
select id, name, addr from student;
select id, name, addr from student where name = 'lixiaosi';
# 删除数据
delete from student where id = '1001';联合主键
1
2
3
4
5
6
7
8
9CREATE TABLE IF NOT EXISTS us_population (
State CHAR(2) NOT NULL,
City VARCHAR NOT NULL,
Population BIGINT
CONSTRAINT my_pk PRIMARY KEY (state, city)
);
upsert into us_population values('NY','New York',8143197) ;
upsert into us_population values('CA','Los Angeles',3844829) ;表的映射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30# Hbase中没有表,phoenix中创建表会同时在hbase中也创建表
# Hbase中有表, 可以在phoenix中创建视图(只读)进行映射
create 'emp','info'
put 'emp','1001','info:name','zhangsan'
put 'emp','1001','info:addr','beijing'
create view "emp"(
id varchar primary key,
"info"."name" varchar,
"info"."addr" varchar
);
# 可以直接查到内容
select * from "emp";
select id , "name","addr" from "emp";
# 只读表修改会报错
upsert into "emp" values('1002','lisi','shanghai');
drop view "emp";
# Hbase中有表, 可以在phoenix中创建表进行映射(读写)
create table "emp"(
id varchar primary key ,
"info"."name" varchar,
"info"."addr" varchar
) COLUMN_ENCODED_BYTES = NONE;
# 需要关闭编码才能查到内容
select * from "emp";
select id , "name","addr" from "emp" ;
drop table "emp";数值问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33# phoenix存,phoenix查.没有问题
# hbase存,hbase查,没有问题
# phoenix存,hbase查.有问题
# hbase存,phoenix查,有问题
# phoenix存/取有符号数值时会取反最高位
# 若要用数字则用无符号数字或不要穿插操作
# 有问题
create table test (
id varchar primary key,
name varchar,
salary integer
)COLUMN_ENCODED_BYTES = NONE;
upsert into test values('1001','zs',123456);
put 'TEST','1002','0:NAME','ls';
# Shell方式默认Long类型
put 'TEST','1002','0:SALARY',Bytes.toBytes(456789);
# 解决
create table test1 (
id varchar primary key,
name varchar,
# 无符号数字
salary UNSIGNED_INT
)COLUMN_ENCODED_BYTES = NONE;
upsert into test1 values('1001','zs',123456);
put 'TEST1','1002','0:NAME','ls';
# Shell方式默认Long类型
put 'TEST1','1002','0:SALARY',Bytes.toBytes(456789);
API
依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<!-- 薄客户端 -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-queryserver-client</artifactId>
<version>6.0.0</version>
</dependency>
<!-- 厚客户端 -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
<version>5.1.2</version>
<exclusions>
<exclusion>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b12</version>
</dependency>代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public static void main(String[] args) throws SQLException {
// 薄客户端获取连接
String url = "jdbc:phoenix:thin:url=http://bigdata1:8765;serialization=PROTOBUF";
Connection connection = DriverManager.getConnection(url);
// 厚客户端获取连接
String url = "jdbc:phoenix:bigdata1,bigdata2,bigdata3:2181";
Properties props = new Properties();
props.put("phoenix.schema.isNamespaceMappingEnabled","true");
Connection connection = DriverManager.getConnection(url, props);
// 获取连接
Connection connection = DriverManager.getConnection(url);
// 编写SQL
String sql = "select id,name,addr from student";
// 预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 执行SQL
ResultSet resultSet = preparedStatement.executeQuery();
// 封装结果
while (resultSet.next()) {
System.out.println(resultSet.getString("id") + " : " +
resultSet.getString("name") + " : " +
resultSet.getString("addr")
);
}
// 关闭连接
resultSet.close();
preparedStatement.close();
connection.close();
}
二级索引
二级索引:给RowKey之外的列建索引
配置文件:HBase的HRegionserver节点的hbase-site.xml
1
2
3
4
5<!-- phoenix regionserver 配置参数-->
<property>
<name>hbase.regionserver.wal.codec</name>
<value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>全局二级索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42# 索引会创建一张索引表,在索引表中将索引列与原表中的rowkey组合起来作为索引表的rowkey
CREATE TABLE IF NOT EXISTS student(
id VARCHAR primary key,
name VARCHAR,
addr VARCHAR
);
# FULL SCAN
explain select id from student;
# POINT LOOKUP(必须唯一)
explain select id from student where id = '1002';
# FULL SCAN
explain select id from student where name = 'lixiaosi';
# 给name字段建索引
create index idx_student_name on student(name);
# RANGE SCAN
explain select id from student where name = 'lixiaosi';
# POINT LOOKUP
explain select id ,name from student where id ='1001';
# RANGE SCAN
explain select id ,name from student where name = 'lixiaosi';
# FULL SCAN
explain select id ,name ,addr from student where name ='lixiaosi';
# 给name addr建复合索引
drop index idx_student_name on student;
create index idx_student_name on student(name,addr);
# RANGE SCAN
explain select id ,name ,addr from student where name ='lixiaosi';
# RANGE SCAN
explain select id ,name ,addr from student where name ='lixiaosi' and addr = 'beijing';
# FULL SCAN:需要先查询name
explain select id ,name ,addr from student where addr = 'beijing';
# RANGE SCAN:会被优化
explain select id ,name ,addr from student where addr = 'beijing' and name ='lixiaosi';
#给name列建索引包含addr列:只需要查,不需要过滤的情况
drop index idx_student_name on student;
create index idx_student_name on student(name) include(addr);
# RANGE SCAN
explain select id, name, addr from student where name = 'lixiaosi';本地二级索引
1
2
3
4
5# 把全局二级索引的表放到原表中
drop index idx_student_name on student;
create local index idx_student_name on student(name);
# RANGE SCAN
explain select id ,name ,addr from student where name = 'lixiaosi';
Hive
对比
- Hive
- 数据分析工具:相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询
- 用于数据分析、清洗:适用于离线的数据分析和清洗,延迟较高
- 基于HDFS、MapReduce:存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行
- HBase
- 数据库:是一种面向列族存储的非关系型数据库
- 用于存储结构化和非结构化的数据:适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作
- 基于HDFS:数据持久化存储的体现形式是HFile,存放于DataNode中,被ResionServer以region的形式进行管理
- 延迟较低,接入在线业务使用:可以直线单表大量数据的存储,同时提供了高效的数据访问速度
- Hive
集成
在hive-site.xml中添加zookeeper的属性
1
2
3
4
5
6
7
8
9<property>
<name>hive.zookeeper.quorum</name>
<value>bigdata1,bigdata2,bigdata3</value>
</property>
<property>
<name>hive.zookeeper.client.port</name>
<value>2181</value>
</property>案例1:在hive中建表,对应着在hbase中也建表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
-- 存储格式
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
-- HBase字段名映射
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
-- HBase表名映射
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
-- 使用中间表导入数据
CREATE TABLE emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
LOAD DATA LOCAL INPATH '/../..' INTO TABLE emp;
INSERT INTO hive_hbase_emp_table SELECT * FROM emp;案例2:Hbase中已经有表, hive建表进行关联
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15-- 只能创建外部表
CREATE EXTERNAL TABLE relevance_hbase_emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY
'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" =
":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");