HBase详解(05) - HBase优化 整合Phoenix 集成Hive

HBase详解(05) - HBase优化 整合Phoenix 集成Hive

HBase优化

预分区

每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护。那么依照这个原则,可以将数据所要投放的分区提前大致的规划好,以提高HBase性能。

1.手动设定预分区

hbase> create 'staff1','info',SPLITS => ['1000','2000','3000','4000']

2.生成16进制序列预分区

create 'staff2','info',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}

3.按照文件中设置的规则预分区

创建splits.txt文件内容如下:

aaaa

bbbb

cccc

dddd

然后执行:

create 'staff3','info',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);

RowKey设计

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。rowkey常用的设计方案:

  1. 生成随机数、hash、散列值

一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。rowkey常用的设计方案:

比如:

原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7

原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd

原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913

在做此操作之前,一般会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

2.字符串反转

20170524000001转成10000042507102

20170524000002转成20000042507102

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

3.字符串拼接

20170524000001_a12e

20170524000001_93i7

内存优化

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

基础优化

1.Zookeeper会话超时时间

hbase-site.xml

属性:zookeeper.session.timeout

解释:默认值为90000毫秒(90s)。当某个RegionServer挂掉,90s之后Master才能察觉到。可适当减小此值,以加快Master响应,可调整至60000毫秒。

2.设置RPC监听数量

hbase-site.xml

属性:hbase.regionserver.handler.count

解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

3.手动控制Major Compaction

hbase-site.xml

属性:hbase.hregion.majorcompaction

解释:默认值:604800000秒(7天), Major Compaction的周期,若关闭自动Major Compaction,可将其设为0

4.优化HStore文件大小

hbase-site.xml

属性:hbase.hregion.max.filesize

解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

5.优化HBase客户端缓存

hbase-site.xml

属性:hbase.client.write.buffer

解释:默认值2097152bytes(2M)用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

6.指定scan.next扫描HBase所获取的行数

hbase-site.xml

属性:hbase.client.scanner.caching

解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

7.BlockCache占用RegionServer堆内存的比例

hbase-site.xml

属性:hfile.block.cache.size

解释:默认0.4,读请求比较多的情况下,可适当调大

8.MemStore占用RegionServer堆内存的比例

hbase-site.xml

属性:hbase.regionserver.global.memstore.size

解释:默认0.4,写请求较多的情况下,可适当调大

HBase整合Phoenix

Phoenix简介

Phoenix定义:PhoenixHBase的开源SQL皮肤。可以使用标准JDBC API代替HBase客户端API来创建表,插入数据和查询HBase数据。

Phoenix特点

1)容易集成:如Spark,Hive,Pig,Flume和Map Reduce;

2)操作简单:DML命令以及通过DDL命令创建和操作表和版本化增量更改;

3)支持HBase二级索引创建。

Phoenix架构

Phoenix 安装

1.下载

官网地址:http://phoenix.apache.org/

下载地址:https://downloads.apache.org/phoenix/

5.0.0版本下载地址:https://downloads.apache.org/phoenix/apache-phoenix-5.0.0-HBase-2.0/bin/apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz

2.Phoenix部署

1)上传并解压tar

[hadoop@hadoop102 software]$ tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /opt/module/

重命名

[hadoop@hadoop102 software]$ cd /opt/module/

[hadoop@hadoop102 module]$ mv apache-phoenix-5.0.0-HBase-2.0-bin/ phoenix

2)复制server包并拷贝到各个HBase节点的hbase/lib

[hadoop@hadoop102 phoenix]$ cp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar /opt/module/hbase/lib/

[hadoop@hadoop102 phoenix]$ scp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar hadoop103:/opt/module/hbase/lib/

[hadoop@hadoop102 phoenix]$ scp /opt/module/phoenix/phoenix-5.0.0-HBase-2.0-server.jar hadoop104:/opt/module/hbase/lib/

4)配置环境变量(可选)

#phoenix

export PHOENIX_HOME=/opt/module/phoenix

export PHOENIX_CLASSPATH=$PHOENIX_HOME

export PATH=$PATH:$PHOENIX_HOME/bin

5)重启Hbase

[hadoop@hadoop102 ~]$ stop-hbase.sh

[hadoop@hadoop102 ~]$ start-hbase.sh

6) 连接Phoenix

[hadoop@hadoop102 ~]$ /opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

7) 退出Phoenix

!quit

Phoenix Shell操作

默认情况下,在phoenix中不能直接创建schema。需要将下面的参数添加到Hbase中conf目录下的hbase-site.xml和phoenix中bin目录下的 hbase-site.xml中

<property>

<name>phoenix.schema.isNamespaceMappingEnabled</name>

<value>true</value>

</property>

修改Hbase的的hbase-site.xml文件

[hadoop@hadoop102 ~]$ vi /opt/module/hbase/conf/hbase-site.xml

将修改后的文件同步到其他机器

[hadoop@hadoop102 conf]$ scp hbase-site.xml hadoop103:/opt/module/hbase/conf/

[hadoop@hadoop102 conf]$ scp hbase-site.xml hadoop104:/opt/module/hbase/conf/

修改phoenix的 hbase-site.xml文件

[hadoop@hadoop102 ~]$ vi /opt/module/phoenix/bin/hbase-site.xml

重新启动Hbase和连接phoenix客户端.

stop-hbase.sh

start-hbase.sh

/opt/module/phoenix/bin/sqlline.py hadoop102,hadoop103,hadoop104:2181

创建schema

create schema bigdata;

注意:phoenix中,schema名,表名,字段名等会自动转换为大写,若要小写,使用双引号,如"student"

1)显示所有表

!table 或 !tables

2)创建表

直接指定单个列作为RowKey

CREATE TABLE IF NOT EXISTS student(

id VARCHAR primary key,

name VARCHAR,

addr VARCHAR);

指定多个列的联合作为RowKey

CREATE TABLE IF NOT EXISTS us_population (

State CHAR(2) NOT NULL,

City VARCHAR NOT NULL,

Population BIGINT

CONSTRAINT my_pk PRIMARY KEY (state, city));

3)插入数据

upsert into student values('1001','zhangsan','beijing');

4)查询记录

select * from student;

select * from student where id='1001';

5)删除记录

delete from student where id='1001';

6)删除表

drop table student;

7)退出命令行

!quit

1)表的关系

默认情况下,直接在HBase中创建的表,通过Phoenix是查看不到的。如果要在Phoenix中操作直接在HBase中创建的表,则需要在Phoenix中进行表的映射。映射方式有两种:视图映射和表映射。

2)命令行中创建表test

HBase test的表结构如下,两个列族info1info2

Rowkey    info1    info2

id    name    address

启动HBase Shell

/opt/module/hbase/bin/hbase shell

创建HBasetest

hbase(main):001:0> create 'test','info1','info2'

3)视图映射

Phoenix创建的视图是只读的,所以只能用来做查询,无法通过视图对源数据进行修改等操作。在phoenix中创建关联test表的视图

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> create view "test"(id varchar primary key,"info1"."name" varchar, "info2"."address" varchar);

删除视图

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> drop view "test";

4)表映射

使用Apache Phoenix创建对HBase的表映射,有两种方法:

1HBase中不存在表时,可以直接使用create table指令创建需要的表,系统将会自动在PhoenixHBase中创建person_infomation的表,并会根据指令内的参数对表结构进行初始化。

2)当HBase中已经存在表时,可以以类似创建视图的方式创建关联表,只需要将create view改为create table即可。

0: jdbc:phoenix:hadoop101,hadoop102,hadoop103> create table "test"(id varchar primary key,"info1"."name" varchar, "info2"."address" varchar) column_encoded_bytes=0;

Hbase中存储数值类型的值(如int,long等)会按照正常数字的补码进行存储. 而phoenix对数字的存储做了特殊的处理. phoenix 为了解决遇到正负数同时存在时,导致负数排到了正数的后面(负数高位为1,正数高位为0,字典序0 < 1)的问题。 phoenix在存储数字时会对高位进行转换.原来为1,转换为0, 原来为0,转换为1.

因此,如果hbase表中的数据的写是由phoenix写入的,不会出现问题,因为对数字的编解码都是phoenix来负责。如果hbase表中的数据不是由phoenix写入的,数字的编码由hbase负责. 而phoenix读数据时要对数字进行解码。 因为编解码方式不一致。导致数字出错.

hbase(main):001:0> create 'person','info'

hbase(main):001:0> put 'person','1001', 'info:salary',Bytes.toBytes(123456)

注意: 如果要插入数字类型,需要通过Bytes.toBytes(123456)来实现。

2)在phoenix中创建映射表并查询数据

create table "person"(id varchar primary key,"info"."salary" integer ) column_encoded_bytes=0;

 

select * from "person";

在查询结果中会发现数字显示有问题

在phoenix中创建表时使用无符号的数值类型. unsigned_long

create table "person"(id varchar primary key,"info"."salary" unsigned_long ) column_encoded_bytes=0;

Phoenix JDBC操作

[hadoop@hadoop102 ~]$ cd /opt/module/phoenix/

[hadoop@hadoop102 phoenix]$ bin/queryserver.py start

2)创建新项目并导入依赖

<dependencies>

<dependency>

<groupId>org.apache.phoenix</groupId>

<artifactId>phoenix-queryserver-client</artifactId>

<version>5.0.0-HBase-2.0</version>

</dependency>

</dependencies>

package com.zhangjk.phoenix;

import java.sql.*;

import org.apache.phoenix.queryserver.client.ThinClientUtil;

 

public class PhoenixTest {

public static void main(String[] args) throws SQLException {

 

String connectionUrl = ThinClientUtil.getConnectionUrl("hadoop102", 8765);

Connection connection = DriverManager.getConnection(connectionUrl);

PreparedStatement preparedStatement = connection.prepareStatement("select * from student3");

 

ResultSet resultSet = preparedStatement.executeQuery();

while (resultSet.next()) {

System.out.println(resultSet.getString(1) + "\t" + resultSet.getString(2));

}

//关闭

connection.close();

}

}

1)在pom中加入依赖

<dependencies>

<dependency>

<groupId>org.apache.phoenix</groupId>

<artifactId>phoenix-core</artifactId>

<version>5.0.0-HBase-2.0</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-b06</version>

</dependency>

</dependencies>

2)编写代码

package com.zhangjk.phoenix;

import java.sql.*;

import java.util.Properties;

 

public class TestThick {

 

public static void main(String[] args) throws SQLException {

String url = "jdbc:phoenix:hadoop102,hadoop103,hadoop104:2181";

Properties props = new Properties();

props.put("phoenix.schema.isNamespaceMappingEnabled","true");

Connection connection = DriverManager.getConnection(url,props);

PreparedStatement ps = connection.prepareStatement("select * from student3");

ResultSet rs = ps.executeQuery();

while(rs.next()){

System.out.println(rs.getString(1)+":" +rs.getString(2));

}

}

}

Phoenix二级索引

添加如下配置到HBase的HRegionserver节点的hbase-site.xml

<!-- phoenix regionserver 配置参数-->

<property>

<name>hbase.regionserver.wal.codec</name>

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

</property>

 

<property>

<name>hbase.region.server.rpc.scheduler.factory.class</name>

<value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>

<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>

</property>

 

<property>

<name>hbase.rpc.controllerfactory.class</name>

<value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>

<description>Factory to create the Phoenix RPC Scheduler that uses separate queues for index and metadata updates</description>

</property>

Global Index默认的索引格式,创建全局索引时,会在HBase中建立一张新表。也就是说索引数据和数据表是存放在不同的表中的,因此全局索引适用于多读少写的业务场景。

写数据的时候会消耗大量开销,因为索引表也要更新,而索引表是分布在不同的数据节点上的,跨节点的数据传输带来了较大的性能消耗。

在读数据的时候Phoenix会选择索引表来降低查询消耗的时间。

1.创建单个字段的全局索引

CREATE INDEX my_index ON my_table (my_col);

如果想查询的字段不是索引字段的话索引表不会被使用,也就是说不会带来查询速度的提升。

创建携带其他字段的全局索引

CREATE INDEX my_index ON my_table (v1) INCLUDE (v2);

Local Index适用于写操作频繁的场景。

索引数据和数据表的数据是存放在同一张表中(且是同一个Region),避免了在写操作的时候往不同服务器的索引表中写索引带来的额外开销。

CREATE LOCAL INDEX my_index ON my_table (my_column);

与Hive的集成

HBase与Hive的对比

(1) 数据分析工具

Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询。

(2) 用于数据分析、清洗

Hive适用于离线的数据分析和清洗,延迟较高。

(3) 基于HDFSMapReduce

Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行。

(1) 数据库

是一种面向列族存储的非关系型数据库。

(2) 用于存储结构化和非结构化的数据

适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作。

(3) 基于HDFS

数据持久化存储的体现形式是HFile,存放于DataNode中,被ResionServerregion的形式进行管理。

(4) 延迟较低,接入在线业务使用

面对大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度。

HBase与Hive集成使用

hive-site.xml中添加zookeeper的属性,如下:

<property>

<name>hive.zookeeper.quorum</name>

<value>hadoop102,hadoop103,hadoop104</value>

</property>

 

<property>

<name>hive.zookeeper.client.port</name>

<value>2181</value>

</property>

案例一

目标:建立Hive表,关联HBase表,插入数据到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");

提示:完成之后,可以分别进入Hive和HBase查看,都生成了对应的表

2.Hive中创建临时中间表,用于load文件中的数据

提示:不能将数据直接load进Hive所关联HBase的那张表中

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.Hive中间表中load数据

hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;

4.通过insert命令将中间表中的数据导入到Hive关联Hbase的那张表中

hive> insert into table hive_hbase_emp_table select * from emp;

5.查看Hive以及关联的HBase表中是否已经成功的同步插入了数据

Hive:

hive> select * from hive_hbase_emp_table;

HBase:

Hbase> scan 'hbase_emp_table'

案例二

目标:HBase中已经存储了某一张表hbase_emp_table,然后在Hive中创建一个外部表来关联HBase中的hbase_emp_table这张表,使之可以借助Hive来分析HBase这张表中的数据。

注:该案例2基于案例1,所以完成此案例前,请先完成案例1

分步实现:

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");

hive (default)> select * from relevance_hbase_emp;

posted @   莲藕淹  阅读(252)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示