Hbase学习视频心得(三)Phoenix使用全过程、Hbase与Hive集成使用、Hbase优化

文章目录

1、Phoenix搭建(Phoenix 4.15 HBase 1.4.6 hadoop 2.7.6)

1)、关闭hbase集群,在master中执行

stop-hbase.sh

2)、上传解压配置环境变量

解压

tar -xvf apache-phoenix-4.15.0-HBase-1.4-bin.tar.gz 

改名

mv apache-phoenix-4.15.0-HBase-1.4-bin phoenix-4.15.0

配置环境变量

#phoenix
export PHOENIX_HOME=/usr/local/soft/phoenix-4.15.0
export PHOENIX_CLASSPATH=$PHOENIX_HOME
export PATH=$PATH:$PHOENIX_HOME/bin

3)、将phoenix-4.15.0-HBase-1.4-server.jar复制到所有节点的hbase lib目录下

scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar master:/usr/local/soft/hbase-1.4.6/lib/

scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node1:/usr/local/soft/hbase-1.4.6/lib/

scp /usr/local/soft/phoenix-4.15.0/phoenix-4.15.0-HBase-1.4-server.jar node2:/usr/local/soft/hbase-1.4.6/lib/

4)、启动hbase , 在master中执行

start-hbase.sh

5)、连接sqlline

sqlline.py master,node1,node2

# 出现,成功!
163/163 (100%) Done
Done
sqlline version 1.5.0
0: jdbc:phoenix:master,node1,node2> 

2、Phoenix Shell基本操作

1)、基本操作

--1、创建表

CREATE TABLE IF NOT EXISTS STUDENT (
 id VARCHAR NOT NULL PRIMARY KEY, 
 name VARCHAR,
 age BIGINT, 
 gender VARCHAR ,
 clazz VARCHAR
);

--2、显示所有表
 !table

--3、插入数据
upsert into STUDENT values('1500100004','葛德曜',24,'男','理科三班');
upsert into STUDENT values('1500100005','宣谷芹',24,'男','理科六班');
upsert into STUDENT values('1500100006','羿彦昌',24,'女','理科三班');

--4、查询数据
select * from STUDENT ;
select * from STUDENT where age=24;


--5、删除数据
delete from STUDENT where id='1500100004';

--6、删除表
drop table STUDENT;
 
--7、退出命令行
!quit

2)、表的映射

①、视图映射:

在hbase shell创建表并存储数据

--建表
create 'fruit','info'

--插入数据
put 'fruit','1001','info:name','apple'

put 'fruit','1002','info:name','pinapple'

put 'fruit','1001','info:color','red'

put 'fruit','1002','info:color','yellow'

--扫描该表
scan 'fruit'

--结果展示
 ROW                   COLUMN+CELL                                               
 1001                 column=info:color, timestamp=1611238657236, value=red     
 1001                 column=info:name, timestamp=1611238624978, value=apple    
 1002                 column=info:color, timestamp=1611238673993, value=yellow  
 1002                 column=info:name, timestamp=1611238638719, value=pinapple 

在Phoenix Shell建立视图映射

--创建视图表
create view "fruit"
(id varchar primary key,
"info"."name" varchar,
"info"."color" varchar);

--查询该表
select * from "fruit";

--结果展示
+-------+-----------+---------+
|  ID   |   name    |  color  |
+-------+-----------+---------+
| 1001  | apple     | red     |
| 1002  | pinapple  | yellow  |
+-------+-----------+---------+

补充:Table is read only(创建的视图是只读的,所以只能用来做查询)

②、表映射:

在Phoenix Shell建立表映射

create table "fruit"
(id varchar primary key,
"info"."name" varchar,
"info"."color" varchar)
column_encoded_bytes=0;

补充:创建视图映射是为了保护表中的数据,视图映射表删除hbase上表格还在,表映射删除表格,hbase上的表也就对应的删除了。

3、Phoenix JDBC操作

1)、导入maven依赖

<dependencies>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.4.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.4.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.6</version>
        </dependency>

        <dependency>
            <groupId>org.apache.phoenix</groupId>
            <artifactId>phoenix-core</artifactId>
            <version>4.15.0-HBase-1.4</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.3.6</version>
        </dependency>

    </dependencies>

2)、jdbc代码

public class phoenix_jdbc {
    public static void main(String[] args) throws SQLException {
        Connection connection = DriverManager.getConnection("jdbc:phoenix:master,node1,node2:2181");

        PreparedStatement ps = connection.prepareStatement("select mdn,x,y,county from dianxin where x=? and y =?");
        ps.setDouble(1, 117.288);
        ps.setDouble(2, 31.822);

        ResultSet resultSet = ps.executeQuery();
        while (resultSet.next()) {
            String mdn = resultSet.getString("mdn");
            double x = resultSet.getDouble("x");
            double y = resultSet.getDouble("y");

            String county = resultSet.getString("county");

            System.out.println(mdn + "\t" + x + "\t" + y + "\t" + county);
        }
        connection.close();
    }
}

4、Phoenix二级索引

对于Hbase,如果想精确定位到某行记录,唯一的办法就是通过rowkey查询。如果不通过rowkey查找数据,就必须逐行比较每一行的值,对于较大的表,全表扫描的代价是不可接受的。

1)、开启索引支持

# 关闭hbase集群
stop-hbase.sh

# 在hbase-site.xml中增加如下配置

<property>
  <name>hbase.regionserver.wal.codec</name>
  <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
</property>

# 同步到所有节点
scp hbase-site.xml node1:`pwd`
scp hbase-site.xml node2:`pwd`


# 启动hbase
start-hbase.sh

2)、创建索引

①、全局索引

全局索引适合读多写少的场景。如果使用全局索引,读数据基本不损耗性能,所有的性能损耗都来源于写数据。数据表的添加、删除和修改都会更新相关的索引表(数据删除了,索引表中的数据也会删除;数据增加了,索引表的数据也会增加)

注意: 对于全局索引在默认情况下,在查询语句中检索的列如果不在索引表中,Phoenix不会使用索引表将,除非使用hint。

# 创建DIANXIN.sql
CREATE TABLE IF NOT EXISTS DIANXIN (
     mdn VARCHAR ,
     start_date VARCHAR ,
     end_date VARCHAR ,
     county VARCHAR,
     x DOUBLE ,
     y  DOUBLE,
     bsid VARCHAR,
     grid_id  VARCHAR,
     biz_type VARCHAR, 
     event_type VARCHAR , 
     data_source VARCHAR ,
     CONSTRAINT PK PRIMARY KEY (mdn,start_date)
);

# 上传数据DIANXIN.csv

# 导入数据
psql.py master,node1,node2 DIANXIN.sql DIANXIN.csv

# 创建全局索引
CREATE INDEX DIANXIN_INDEX ON DIANXIN ( end_date );

# 查询数据 ( 索引未生效)
select * from DIANXIN where end_date = '20180503154014';

# 强制使用索引 (索引生效) hint
select /*+ INDEX(DIANXIN DIANXIN_INDEX) */  * from DIANXIN where end_date = '20180503154014'  and start_date = '20180503154614';

# 取索引列,(索引生效)
select end_date from DIANXIN where end_date = '20180503154014';
select and,end_date from DIANXIN where end_date = '20180503154014';

# 创建多列索引
CREATE INDEX DIANXIN_INDEX1 ON DIANXIN ( end_date,start_data );

# 多条件查询 (索引生效)
select end_date from DIANXIN where end_date = '20180503154014' and start_date = '20180503154614';

# 查询所有列 ( 索引未生效)
select  * from DIANXIN where end_date = '20180503154014' and start_date = '20180503154614';

# 查询所有列 (索引生效)
select /*+ INDEX(DIANXIN DIANXIN_INDEX) */ * from DIANXIN where end_date = '20180503154014' and start_date = '20180503154614';

# 单条件  ( 索引未生效)
select end_date from DIANXIN where  start_date = '20180503154614';

注意:全局索引的代价,占空间是肯定的,插入数据也会变慢

②、本地索引

本地索引适合写多读少的场景,或者存储空间有限的场景。和全局索引一样,Phoenix也会在查询的时候自动选择是否使用本地索引。本地索引因为索引数据和原数据存储在同一台机器上,避免网络数据传输的开销,所以更适合写多的场景。由于无法提前确定数据在哪个Region上,所以在读数据的时候,需要检查每个Region上的数据从而带来一些性能损耗。

注意:对于本地索引,查询中无论是否指定hint或者是查询的列是否都在索引表中,都会使用索引表。

@ 创建本地索引
CREATE LOCAL INDEX DIANXIN_LOCAL_IDEX ON DIANXIN(grid_id);

# 索引生效
select grid_id from dianxin where grid_id='117285031820040'

# 索引生效
select * from dianxin where grid_id='117285031820040'

注意:本地索引是在hbase表里插入格外的一批值,这批值只有主键没有value,查找原理:通过过滤的信息查找到表的主键再通过主键查找这一行的信息,因此查找 * 是可以的。

③、覆盖索引

覆盖索引是把原数据存储在索引数据表中,这样在查询时不需要再去HBase的原表获取数据就,直接返回查询结果。

注意:查询是 select 的列和 where 的列都需要在索引中出现。

# 创建覆盖索引
CREATE INDEX DIANXIN_INDEX_COVER ON DIANXIN ( x,y ) INCLUDE ( county_id );

# 查询所有列 (索引未生效)
select * from dianxin where x=117.288 and y =31.822;

# 强制使用索引 (索引生效)
select /*+ INDEX(DIANXIN DIANXIN_INDEX_COVER) */ * from dianxin where x=117.288 and y =31.822;

# 查询所索引中的列 (索引生效)
select x,y,county_id from dianxin where x=117.288 and y =31.822;

查询条件必须放在索引中  select 中的列可以放在INCLUDE (将数据保存在索引中)

3)、对比

查找:全局索引和本地索引在单纯查找这一方面肯定是全局查找快!因为全局是一次查找出结果,而本地是二次查找.

空间代价:全局代价比本地高

插入,修改:本地插入、修改更快

因而本地适合读少写多,全局适合读多写少

5、Hbase与Hive的集成

1)、二者对比

一.Hive
(1) 数据仓库
Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询。
(2) 用于数据分析、清洗
Hive适用于离线的数据分析和清洗,延迟较高。
(3) 基于HDFS、MapReduce
Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行。

二.HBase
(1) 数据库
是一种面向列族存储的非关系型数据库。
(2) 用于存储结构化和非结构化的数据
适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作。
(3) 基于HDFS
数据持久化存储的体现形式是HFile,存放于DataNode中,被ResionServer以region的形式进行管理。
(4) 延迟较低,接入在线业务使用
面对大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度。

★2)、HBase与Hive集成使用

HBase与Hive的集成在最新的两个版本中无法兼容。所以,我们只能重新编译:hive-hbase-handler-1.2.2.jar!

编译过程附上网上大佬的流程网址https://www.jianshu.com/p/425df8dbca11

/*案例1:*/
--1、在Hive中创建表同时关联HBase
CREATE 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'
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");

--2、在hive里面创建中间表,做数据分析
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';

--3、导入数据分析的结果,例如:通过insert命令将中间表中的数据导入到Hive关联Hbase的那张表中
insert into table hive_hbase_emp_table select * from emp where sal>2000;

--4、phoenix编写视图最后结果显示(供其他团队使用)
create view "hbase_emp_table"(
empno varchar primary key,
"info"."ename" varchar,
"info"."job" varchar,
"info"."mgr" varchar,
"info"."hiredate" varchar,
"info"."sal" varchar,
"info"."comm" varchar,
"info"."deptno" varchar);


/*案例2:*/
--1、在Hive中创建外部表,可以用来做数据分析
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");

--2、hive外部表修改hbase表也会修改
insert into table relevance_hbase_emp select * from emp;

注意:这样在hive建表,hdfs上是没有数据的

3)、附录带重编译过程:

1、下载Hive源码地址

http://archive.apache.org/dist/hive/hive-1.2.1/

img

2、解压Hive源码

img

3、进入Hive源码,把hbase-handler模块引入Eclipse项目中

img

4、创建Java Project

img

img

img

5、创建lib文件夹

img

img

6、导入Hive源码的hbase-handler模块

img

img

img

7、把Hive和HBase 安装包lib目录下的所有jar包,复制到java project的lib目录下

img

8、把lib包下的所有jar包Build Path,添加到类路径

img

9、打包项目,开始重新编译

img

img

img

10、替换hive/lib目录下的hive-hbase-handler-1.2.1.jar

[victor@node1 ~]$ cp hive-hbase-handler-1.2.1.jar $HIVE_HOME/lib/hive-hbase-handler-1.2.1.jar

6、Hbase的优化

1)、预分区

如果面对大量的数据,并且我们提前知道该数据可能要分区,为了防止在以后的使用过程中频繁分区,因而做一个提前的预分区。

1.手动设定预分区
Hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000']

2.生成16进制序列预分区
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

3.按照文件中设置的规则预分区
创建splits.txt文件内容如下:
aaaa
bbbb
cccc
dddd
然后执行:
create 'staff3','partition3',SPLITS_FILE => 'splits.txt'

4.使用JavaAPI创建预分区
//自定义算法,产生一系列hash散列值存储在二维数组中
byte[][] splitKeys = 某个散列值函数
//创建HbaseAdmin实例
HBaseAdmin hAdmin = new HBaseAdmin(HbaseConfiguration.create());
//创建HTableDescriptor实例
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
//通过HTableDescriptor实例和散列值二维数组创建带有预分区的Hbase表
hAdmin.createTable(tableDesc, splitKeys);

2)、RowKey设计

①、生成随机数、hash、散列值

比如:原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

②、字符串反转

20170524000001转成10000042507102
20170524000002转成20000042507102

这样也可以在一定程度上散列逐步put进来的数据。

③、字符串拼接

20170524000001_a12e
20170524000001_93i7

3)、内存优化

HBase操作过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,一般会分配整个可用内存的70%给HBase的Java堆。但是不建议分配非常大的堆内存,因为GC过程持续太久会导致RegionServer处于长期不可用状态,一般16~48G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。

4)、基础优化

//1.允许在HDFS的文件中追加内容
hdfs-site.xml、hbase-site.xml
属性:dfs.support.append
解释:开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true//2.优化DataNode允许的最大文件打开数
hdfs-site.xml
属性:dfs.datanode.max.transfer.threads
解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096

//3.优化延迟高的数据操作的等待时间
hdfs-site.xml
属性:dfs.image.transfer.timeout
解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。

//4.优化数据的写入效率
mapred-site.xml
属性:
mapreduce.map.output.compress
mapreduce.map.output.compress.codec
解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。

//5.设置RPC监听数量
hbase-site.xml
属性:Hbase.regionserver.handler.count
解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

//6.优化HStore文件大小
hbase-site.xml
属性:hbase.hregion.max.filesize
解释:默认值1073741824010GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

//7.优化HBase客户端缓存
hbase-site.xml
属性:hbase.client.write.buffer
解释:用于指定Hbase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

//8.指定scan.next扫描HBase所获取的行数
hbase-site.xml
属性:hbase.client.scanner.caching
解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

//9.flush、compact、split机制
当MemStore达到阈值,将Memstore中的数据Flush进Storefile;compact机制则是把flush出来的小文件合并成大的Storefile文件。split则是当Region达到阈值,会把过大的Region一分为二。
涉及属性:
即:128M就是Memstore的默认阈值
hbase.hregion.memstore.flush.size:134217728
即:这个参数的作用是当单个HRegion内所有的Memstore大小总和超过指定值时,flush该HRegion的所有memstore。RegionServer的flush是通过将请求添加一个队列,模拟生产消费模型来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM。
hbase.regionserver.global.memstore.upperLimit:0.4
hbase.regionserver.global.memstore.lowerLimit:0.38
即:当MemStore使用内存总量达到hbase.regionserver.global.memstore.upperLimit指定值时,将会有多个MemStores flush到文件中,MemStore flush 顺序是按照大小降序执行的,直到刷新到MemStore使用内存略小于lowerLimit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

友培

数据皆开源!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值