分布式NoSQL列存储数据库Hbase
Posted Maynor学长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式NoSQL列存储数据库Hbase相关的知识,希望对你有一定的参考价值。
文章目录
- 分布式NoSQL列存储数据库Hbase(六)
- 知识点01:回顾
- 知识点02:目标
- 知识点03:SQL on Hbase
- 知识点04:Hive on Hbase 介绍
- 知识点05:Hive on Hbase 配置
- 知识点06:Hive on Hbase 实现
- 知识点07:二级索引问题
- 知识点08:Phoenix的介绍
- 知识点09:Phoenix的安装配置
- 知识点10:Phoenix的语法:DDL:NS
- 知识点11:Phoenix的语法:DDL:Table
- 知识点12:Phoenix的语法:DML:upsert
- 知识点13:Phoenix的语法:DML:delete
- 知识点14:Phoenix的语法:DQL:select
- 知识点15:Phoenix的使用:预分区
- 知识点16:Phoenix的使用:加盐salt
- 知识点17:Phoenix的使用:视图
- 知识点18:Phoenix的使用:JDBC
分布式NoSQL列存储数据库Hbase(六)
知识点01:回顾
-
Hbase表的设计
-
Rowkey设计
- 业务原则:将最常用的查询条件的字段作为Rowkey的前缀
- 唯一原则:保证每一个Rowkey表示唯一的一条数据
- 组合原则:尽量将常用的几个查询字段组合作为rowkey
- 散列原则:构建不连续的Rowkey
- 可以不连续字段作为前缀
- 加密:编码规则:Md5
- 反转
- 添加随机值
- 长度原则:保证业务前提,越短越好
-
列族设计
-
长度原则:名称没有别的意义,满足标识以后,越短越好
-
个数原则:列族的个数不超过3个
-
1个:如果列的个数比较少
-
2个或者3个:如果列的个数达到30个及以上
-
-
-
-
Hbase Java API
-
step1:构建连接
Connection conn = ConnectionFactory.getConnect(Configuration)
-
step2:DDL
- 构建admin
-
step3:DML
-
构建Table对象
-
写:Put
Put put = new Put(rowkey) put.addColumn(cf,col,value) table.put(Put)
-
读:Scan
Scan scan = new Scan //过滤器 rowkey范围:startrow和stoprow rowkey前缀:PrefixFilter 列值过滤:SingleColumnValueFilter 列的过滤:MultipleColumnPrefixFilter ResultScanner rsscan = table.getScanner(Scan) //多个rowkey数据的集合 for(Result rs: rsscan) //每个rowkey就是一个Result for(Cell cell:rs.rawCells) //每列的数据
-
-
知识点02:目标
- SQL on Hbase
- 使用SQL语句来操作Hbase
- Hbase不支持SQL接口
- 额外的工具来实现
- 使用SQL语句来操作Hbase
- Hive on Hbase【了解】
- 使用Hive中的SQL语句来实现对Hbase数据的操作
- 本质:通过MapReduce来实现读写Hbase
- Phoenix【重点】
- 专门为Hbase所设计的一个工具
- 本质:直接封装Hbase的JavaAPI来实现的
- 功能、应用场景、基本原理、特点
- 基本使用:语法【upsert、delete、select】
知识点03:SQL on Hbase
-
问题
- Hbase是列存储NoSQL,不支持SQL,开发接口不方便大部分用户使用,怎么办?
-
分析
-
应用场景:应用系统或者大数据存储系统
-
大数据存储系统:大数据工程师
- 利用Hbase来存储大量要分析处理的数据
- 使用JavaAPI通过MapReduce或者通过Spark来实现数据的读写
- Java
- Scala
-
应用系统:Java工程师、数据分析师
- 利用Hbase来存储大量的商品数据、订单数据,来提供高性能的查询
-
问题:Java人员不会Hbase Java API,对于数据库会JDBC
-
解决:需要一个工具能让Hbase支持SQL,支持JDBC方式对Hbase进行处理
-
-
Hbase的结构是否能实现基于SQL的查询操作?
-
普通表数据:按行操作
id name age sex addr 001 zhangsan 18 null shanghai 002 lisi 20 female null 003 wangwu null male beijing ……
-
Hbase数据:按列操作
rowkey cf1:id cf1:name cf1:age cf2:sex cf2:addr zhangsan_001 001 zhangsan 18 null shanghai lisi_002 002 lisi 20 female null wangwu_003 003 wangwu null male beijing ……
-
-
可以基于Hbase数据构建结构化的数据形式
-
可以用SQL来实现处理
-
-
实现
- 将Hbase表中每一行对应的所有列构建一张完整的结构化表
- 如果这一行没有这一列,就补null
- Hive:通过MapReduce来实现
- Phoenix:通过Hbase API封装实现的
-
总结
- 原因:满足各种应用场景下,对于Hbase使用的方式,基于SQL方式会更加通用
- 实现:将整张表的数据构建结构化形式,每一行没有列就补null
- 原理:将SQL转换成了Hbase的客户端操作来实现的
知识点04:Hive on Hbase 介绍
-
功能:实现Hive与Hbase集成,使用Hive SQL对Hbase的数据进行处理
-
原理
-
Hive的功能:使用HQL对表的数据进行处理
-
本质:通过MapReduce对HDFS中的文件进行处理
-
原理
-
TextInputFormat:读文件
-
TextOutputFormat:写文件
-
-
-
MapReduce的功能:读取数据进行分布式计算
-
InputFormat:输入类
- TextInputFormat:默认的输入类,用于读取文件系统
- DBInputFormat:用于读取JDBC数据库
- 实现Sqoop导入的:将mysql数据导入到Hive或者HDFS
- TableInputFormat:用于读取Hbase数据
-
OutputFormat:输出类
-
TextOutputFormat:默认的输出类,用于将结果写入文件系统
-
DBOutputFormat:用于写入JDBC数据库
- 实现Sqoop导出的:将HDFS数据写入MySQL
-
TableOutputFormat:用于写入HBase数据库
-
-
-
原理:Hive可以通过MapReduce来实现映射读写Hbase表的数据
-
-
特点
-
优点:支持完善的SQL语句,可以实现各种复杂SQL的数据处理及计算,通过分布式计算程序实现,对大数据量的数据处理比较友好
-
缺点:不支持二级索引,数据量不是特别大的情况下,性能一般
-
-
应用
- 基于大数据高性能的离线读写,并且使用SQL来开发
知识点05:Hive on Hbase 配置
-
需求
- 配置Hive与Hbase集成,实现Hive中可以读写Hbase表
-
分析
- step1:修改Hive配置文件,指定Hbase的Zookeeper地址
- step2:按顺序启动HDFS、ZK、Hbase、Hive
-
实现
-
全部操作在第三台机器
-
修改hive-site.xml:Hive通过SQL访问Hbase,就是Hbase的客户端,就要连接zookeeper
cd /export/server/hive-2.1.0-bin/ vim conf/hive-site.xml
<property> <name>hive.zookeeper.quorum</name> <value>node1,node2,node3</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>node1,node2,node3</value> </property> <property> <name>hive.server2.enable.doAs</name> <value>false</value> </property>
-
修改hive-env.sh
export HBASE_HOME=/export/server/hbase-2.1.0
-
启动HDFS、ZK、Hbase:第一台机器
start-dfs.sh /export/server/zookeeper-3.4.6/bin/start-zk-all.sh start-hbase.sh
-
启动Hive和YARN:第三台机器
#启动YARN start-yarn.sh #先启动metastore服务 start-metastore.sh #然后启动hiveserver start-hiveserver2.sh #然后启动beeline start-beeline.sh
-
-
总结
- 先配置Hive的配置文件:添加Hbase的地址
- 然后按照先后顺序启动即可
知识点06:Hive on Hbase 实现
-
需求
- 在Hive中实现对Hbase表的数据读写
-
分析
- step1:如果表在Hbase中没有,Hive中没有,在Hive中创建表,指定在Hbase中创建关联表
- 场景比较少
- 在Hive中建一张表,自动在Hbase中也创建一张对应的表
- step2:如果表在Hbase中有,但是Hive中没有,Hive中创建一张外部表,关联Hbase表
- 主要应用的方式
- Hbase中的表已经存在,已经有数据,构建一张Hive关联表,使用SQL进行查询
- step1:如果表在Hbase中没有,Hive中没有,在Hive中创建表,指定在Hbase中创建关联表
-
实现
-
第三台机器测试
-
如果Hbase中表不存在:【用的比较少】
-
创建测试数据文件
vim /export/data/hive-hbase.txt 1,zhangsan,80 2,lisi,60 3,wangwu,30 4,zhaoliu,70
-
创建测试表
--创建测试数据库 create database course; --切换数据库 use course; --创建原始数据表 create external table if not exists course.score( id int, cname string, score int ) row format delimited fields terminated by ',' stored as textfile ; --加载数据文件 load data local inpath '/export/data/hive-hbase.txt' into table score;
-
创建一张Hive与HBASE的映射表
create table course.hbase_score( id int, cname string, score int ) stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties("hbase.columns.mapping" = "cf:name,cf:score") tblproperties("hbase.table.name" = "hbase_score");
-
将测试表的数据写入映射表
set hive.exec.mode.local.auto=true; insert overwrite table course.hbase_score select id,cname,score from course.score;
-
-
如果Hbase中表已存在,只能创建外部表
create external table course.t1( key string, name string, age string, addr string, phone string ) stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' with serdeproperties("hbase.columns.mapping" = ":key,basic:name,basic:age,other:addr,other:phone") tblproperties("hbase.table.name" = "itcast:t1");
-
-
总结
- Hive中的只是关联表,并没有数据,数据存储在Hbase表中
-
在Hive中创建Hbase的关联表,关联成功后,使用SQL处理关联表
- 如果Hbase中表不存在,默认使用Hive的第一列作为rowkey
- 如果Hbase中表已存在,只能建外部表,使用:key来表示rowkey
- HIve中与Hbase关联的表,不能使用load加载,只能使用insert,通过MR读写数据
知识点07:二级索引问题
-
问题
- Hbase使用Rowkey作为唯一索引,需要构建二级索引来解决查询问题,如何构建二级索引以及维护索引表?
-
分析
-
step1:基于存储和常用查询需求,构建数据表
-
step2:基于其他查询需求,构建索引表
-
step3:先查询索引表,再查询数据表
-
step4:自动维护索引表与原始数据表的数据一致性
-
-
实现
-
构建数据表
rowkey:name_id id name age sex addr zhangsan_001 001 zhangsan 18 male shanghai lisi_002 002 lisi 18 female beijing zhangsan_003 003 zhangsan 20 male ……
-
构建索引表
rowkey:id_name col:原始数据表的rowkey 001_zhangsan zhangsan_001 002_lisi lisi_002 003_zhangsan zhangsan_003 ……
-
查询:根据id查询
- 先查询索引表,获取原表的Rowkey
- 再根据原表Rowkey查询原表的数据
-
维护
- 当原表数据需要进行增删改时,索引表自动进行同步增删改对应的数据,保持一致性
-
解决方案
-
方案一:客户端操作实现
put1 put2 table1.put(put1) table2.put(put2)
-
方案二:协处理器实现
- 自己开发代码
- 让Hbase监听原表,原表更改一条,Hbase自动对索引表更改一条
- 缺点:开发比较麻烦
-
方案三:第三方工具
-
Phoenix:将所有协处理器都封装好了
-
支持SQL
-
支持自动二级索引的构建及维护
create index
-
-
-
-
-
总结
- 需求:必须根据不同的查询条件,创建不同的索引表,并且维护所有索引表与原始数据表的同步
- 解决:通过Phoenix自带的协处理器来实现
知识点08:Phoenix的介绍
-
功能
-
专门基于Hbase所设计的SQL on Hbase 工具
-
使用Phoenix实现基于SQL操作Hbase
-
使用Phoenix自动构建二级索引并维护二级索引
-
-
原理
-
上层提供了SQL接口
- 底层全部通过Hbase Java API来实现,通过构建一系列的Scan和Put来实现数据的读写
-
功能非常丰富
- 底层封装了大量的内置的协处理器,可以实现各种复杂的处理需求,例如二级索引等
-
-
特点
- 优点
- 支持SQL接口
- 支持自动维护二级索引
- 缺点
- SQL支持的语法不全面
- Bug比较多
- Hive on Hbase对比
- Hive:SQL更加全面,但是不支持二级索引,底层通过分布式计算工具来实现
- Phoenix:SQL相对支持不全面,但是性能比较好,直接使用HbaseAPI,支持索引实现
- 优点
-
应用
-
Phoenix适用于任何需要使用SQL或者JDBC来快速的读写Hbase的场景
-
或者需要构建及维护二级索引场景
-
知识点09:Phoenix的安装配置
-
需求
- http://phoenix.apache.org/
- 安装部署配置Phoenix,集成Hbase
-
分析
- step1:上传解压安装
- step2:修改配置,指定Hbase连接地址
- step3:启动Phoenix,连接Hbase
-
实现
-
下载:http://phoenix.apache.org/download.html
-
第一台机器上传
cd /export/software/ rz
-
第一台机器解压
tar -zxvf apache-phoenix-5.0.0-HBase-2.0-bin.tar.gz -C /export/server/ cd /export/server/ mv apache-phoenix-5.0.0-HBase-2.0-bin phoenix-5.0.0-HBase-2.0-bin
-
修改三台Linux文件句柄数
vim /etc/security/limits.conf #在文件的末尾添加以下内容,*号不能去掉 * soft nofile 65536 * hard nofile 131072 * soft nproc 2048 * hard nproc 4096
-
将Phoenix所有jar包分发到Hbase的lib目录下
#拷贝到第一台机器 cd /export/server/phoenix-5.0.0-HBase-2.0-bin/ cp phoenix-* /export/server/hbase-2.1.0/lib/ cd /export/server/hbase-2.1.0/lib/ #分发给第二台和第三台 scp phoenix-* node2:$PWD scp phoenix-* node3:$PWD
-
修改hbase-site.xml,添加一下属性
cd /export/server/hbase-2.1.0/conf/ vim hbase-site.xml
<!-- 关闭流检查,从2.x开始使用async --> <property> <name>hbase.unsafe.stream.capability.enforce</name> <value>false</value> </property> <!-- 支持HBase命名空间映射 --> <property> <name>phoenix.schema.isNamespaceMappingEnabled</name> <value>true</value> </property> <!-- 支持索引预写日志编码 --> <property> <name>hbase.regionserver.wal.codec</name> <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value> </property> <!-- 配置NS映射 --> <property> <name>phoenix.schema.isNamespaceMappingEnabled</name> <value>true</value> </property>
-
同步给其他两台机器
scp hbase-site.xml node2:$PWD scp hbase-site.xml node3:$PWD
-
同步给Phoenix
cp hbase-site.xml /export/server/phoenix-5.0.0-HBase-2.0-bin/bin/
-
重启Hbase
stop-hbase.sh start-hbase.sh
-
启动Phoenix
cd /export/server/phoenix-5.0.0-HBase-2.0-bin/ bin/sqlline.py node1:2181
-
测试
!tables
-
-
总结
- 解压安装
- 修改配置
- 启动服务
- 测试环境
知识点10:Phoenix的语法:DDL:NS
-
http://phoenix.apache.org/language/index.html
-
需求
- 实现基于SQL的数据库管理:创建、切换、删除
-
分析
- step1:创建Namespace
- step2:切换Namespace
- step3:删除Namespace
-
实现
-
创建NS
create schema if not exists student;
-
切换NS
use student;
-
删除NS
drop schema if exists student;
-
-
总结
- 基本与SQL语法一致
- 注意:Phoenix中默认会将所有字符转换为大写,如果想要使用小写字母,必须加上双引号
知识点11:Phoenix的语法:DDL:Table
-
需求
- 实现基于SQL的数据表管理:创建、列举、查看、删除
-
分析
- step1:列举当前所有的表
- step2:创建表
- step3:查询表信息
- step4:删除表
-
实现
-
列举
!tables
-
创建
-
语法:http://phoenix.apache.org/language/index.html#create_table
CREATE TABLE my_schema.my_table ( id BIGINT not null primary key, date Date ); CREATE TABLE my_table ( id INTEGER not null primary key desc, m.date DATE not null, m.db_utilization DECIMAL, i.db_utilization ) m.VERSIONS='3'; CREATE TABLE stats.prod_metrics ( host char(50) not null, created_date date not null, txn_count bigint CONSTRAINT pk PRIMARY KEY (host, created_date) ); CREATE TABLE IF NOT EXISTS "my_case_sensitive_table"( "id" char(10) not null primary key, "value" integer ) DATA_BLOCK_ENCODING='NONE',VERSIONS=5,MAX_FILESIZE=2000000 split on (?, ?, ?); CREATE TABLE IF NOT EXISTS my_schema.my_table ( org_id CHAR(15), entity_id CHAR(15), payload binary(1000), CONSTRAINT pk PRIMARY KEY (org_id, entity_id) ) TTL=86400
-
-
-
如果Hbase中没有这个表
use default; create table if not exists ORDER_DTL( ID varchar primary key, C1.STATUS varchar, C1.PAY_MONEY float, C1.PAYWAY integer, C1.USER_ID varchar, C1.OPERATION_DATE varchar, C1.CATEGORY varchar );
-
如果Hbase中已存在会自动关联
create table if not exists ORDER_INFO( "ROW" varchar primary key, "C1"."USER_ID" varchar, "C1"."OPERATION_DATE" varchar, "C1"."PAYWAY" varchar, "C1"."PAY_MONEY" varchar, "C1"."STATUS" varchar, "C1"."CATEGORY" varchar ) column_encoded_bytes=0 ;
-
查看
!desc order_info;
-
删除
drop table if exists order_dtl;
-
-
总结
-
创建表时,必须指定主键作为Rowkey,主键列不能加列族
create table if not exists ORDER_INFO(
–不能这么写
“C1”.“ROW” varchar primary key,
“C1”.“USER_ID” varchar,
“C1”.“OPERATION_DATE” varchar,
“C1”.“PAYWAY” varchar,
“C1”.“PAY_MONEY” varchar,
“C1”.“STATUS” varchar,
“C1”.“CATEGORY” varchar
) column_encoded_bytes=0 ;-
Phoenix 4.8版本之前只要创建同名的Hbase表,会自动关联数据
-
Phoenix 4.8版本以后,不推荐关联表的方式
- 推荐使用视图关联的方式来实现,如果你要使用关联表的方式,必须加上以下参数
column_encoded_bytes=0 ; ``` - 如果关联已存在的表,Rowkey字段叫做ROW,使用时必须加上双引号
select “ROW”,“C1”.USER_ID,“C1”.“PAYWAY” from ORDER_INFO;
-
知识点12:Phoenix的语法:DML:upsert
列名 | 数值 | 描述 |
---|---|---|
Rowkey | 02602f66-adc7-40d4-8485-76b5632b5b53 | 行健,编码生成 |
USER_ID | 4944191 | 用户id |
OPERATION_DATE | 2020-04-25 12:09:16 | 操作时间 |
PAYWAY | 1 | 支付方式 |
PAY_MONEY | 4070 | 支付金额 |
STATUS | 已提交 | 提交状态 |
CATEGORY | 手机; | 分类 |
-
需求
- 基于order_info订单数据实现DML插入数据
-
分析
-
Phoenix中插入更新的命令为:upsert
- 功能:insert + update
- MySQL:replace
- 如果存在就更新,如果不存在就插入
- 功能:insert + update
-
语法及示例
UPSERT INTO TEST VALUES('foo','bar',3); UPSERT INTO TEST(NAME,ID) VALUES('foo',123); UPSERT INTO TEST(ID, COUNTER) VALUES(123, 0) ON DUPLICATE KEY UPDATE COUNTER = COUNTER + 1; UPSERT INTO TEST(ID, MY_COL) VALUES(123, 0) ON DUPLICATE KEY IGNORE;
-
-
实现
-
插入一条数据
upsert into order_info values('z8f3ca6f-2f5c-44fd-9755-1792de183845','4944191','2020-04-25 12:09:16','1','4070','未提交','电脑');
-
更新USERID为123456
upsert into order_info("ROW","USER_ID") values('z8f3ca6f-2f5c-44fd-9755-1792de183845','123456');
-
-
总结
-
语法类似于insert语法
-
功能:insert + update
-
知识点13:Phoenix的语法:DML:delete
-
需求
- 基于order_info订单数据实现DML删除数据
-
分析
-
Phoenix中插入更新的命令为:delete
-
语法及示例
DELETE FROM TEST; DELETE FROM TEST WHERE ID=123; DELETE FROM TEST WHERE NAME LIKE 'foo%';
-
-
实现
-
删除USER_ID为123456的rowkey数据
delete from order_info where USER_ID = '123456';
-
-
总结
- 与MySQL是一致的
知识点14:Phoenix的语法:DQL:select
-
需求
- 基于order_info订单数据实现DQL查询数据
-
分析
-
Phoenix中插入更新的命令为:select
-
语法及示例
SELECT * FROM TEST LIMIT 1000; SELECT * FROM TEST LIMIT 1000 OFFSET 100; SELECT full_name FROM SALES_PERSON WHERE ranking >= 5.0 UNION ALL SELECT reviewer_name FROM CUSTOMER_REVIEW WHERE score >= 8.0
-
-
实现
-
查询支付方式为1的数据
select "ROW",payway,pay_money,category from order_info where payway = '1';
-
查询每种支付方式对应的用户人数,并且按照用户人数降序排序
- 分组:每、各个、不同
- 排序:用户人数
select payway, count(distinct user_id) as numb from order_info group by payway order by numb desc;
-
查询数据的第60行到66行
--以前的写法:limit M,N --M:开始位置 --N:显示的条数 --Phoenix的写法:limit N offset M select * from order_info limit 6 offset 60;//总共66行,显示最后6行
-
函数支持
- http://phoenix.apache.org/language/functions.html
-
-
总结
- 基本查询与MySQL也是一致的
- 写的时候注意数据类型以及大小写的问题即可
- 如果遇到SQL报错,检查语法是否支持
知识点15:Phoenix的使用:预分区
-
需求
-
Hbase命令建表
create Ns;tbname,列族,预分区
-
创建表的时候,需要根据Rowkey来设计多个分区
-
-
分析
-
Phoenix也提供了创建表时,指定分区范围的语法
CREATE TABLE IF NOT EXISTS "my_case_sensitive_table"( "id" char(10) not null primary key, "value" integer ) DATA_BLOCK_ENCODING='NONE',VERSIONS=5,MAX_FILESIZE=2000000 split on (?, ?, ?)
-
-
实现
-
创建数据表,四个分区
drop table if exists ORDER_DTL; create table if not exists ORDER_DTL( "id" varchar primary key, C1."status" varchar, C1."money" float, C1."pay_way" integer, C1."user_id" varchar, C1."operation_time" varchar, C1."category" varchar ) CONPRESSION='GZ' SPLIT ON ('3','5','7');
-
插入数据
UPSERT INTO "ORDER_DTL" VALUES('02602f66-adc7-40d4-8485-76b5632b5b53','已提交',4070,1,'4944191','2020-04-25 12:09:16','手机;'); UPSERT INTO "ORDER_DTL" VALUES('0968a418-f2bc-49b4-b9a9-2157cf214cfd','已完成',4350,1,'1625615','2020-04-25 12:09:37','家用电器;;电脑;'); UPSERT INTO "ORDER_DTL" VALUES('0e01edba-5e55-425e-837a-7efb91c56630','已提交',6370,3,'3919700','2020-04-25 12:09:39','男装;男鞋;'); UPSERT INTO "ORDER_DTL" VALUES('0f46d542-34cb-4ef4-b7fe-6dcfa5f14751','已付款',9380,1,'2993700','2020-04-25 12:09:46','维修;手机;'); UPSERT INTO "ORDER_DTL" VALUES('1fb7c50f-9e26-4aa8-a140-a03d0de78729','已完成',Day26:分布式NoSQL列存储数据库HBASE
-