1 hbase简介
- hbase是面向列的分布式数据库(DBMS)
- 可伸缩(存储在HDFS中,regionServer可以扩容)
- 高可用,可靠
- 高性能,避免并发
- 面向列,底层存储的数据KV/表结构是以列族为单元
- 稀疏性:每行的数据的属性可能不一致(半结构化数据)
- 数据多版本 以列族为单位 cf1 VERSIONS=3
- 无模式 schema结构不明确
场景
- 表数据的行数几千万条
- 并发性
- hbase不支持SQL ,不适合做报表
- HashMap/根据key(mid)获取数据比较快 快速获取数据的维度单一,例如:
“忠实粉丝”——-> user数据
M
今天的用户 date
20~30岁 —->
签数据/用户画像
依赖环境
- zookeeper
- HDFS底层存储
- JDK
- 时间同步
HBASE架构
- Hmaster
- HRegionServer
- region: 表的行范围数据
- HDFS存储数据
安装部署
start-hbase.sh启动
hbase-shell客户端
- hbase shell
- help
- version whoami status
- create put scan alter
- list desc create_namespace
数据在HDFS上存储的位置信息
/hbase/data/default/table_name/region_name/列族s/hfile文件
hbase hfile -p -f hfile的路径
K: V:
2 SHELL-CMD
2.1 DDL
alter, alter_async, alter_status, clone_table_schema, create, describe,
disable: 禁用表
disable 'table_name' -- 禁用表 禁用的表示不能对表的数据进行操作的禁用的表示可以修改表结构的alter 'tb_a1' , 'delete'=>'cf3'
enable,启用禁用的表
enable 'tb_a1'
disable_all,
enable_all,
hbase(main):021:0> disable_all 't.*'tb_a1tb_a2tb_a3tb_a4tb_aaDisable the above 5 tables (y/n)?y5 tables successfully disabled
hbase(main):022:0> enable_all 't.*'tb_a1tb_a2tb_a3tb_a4tb_aaEnable the above 5 tables (y/n)?y5 tables successfully enabledTook 8.3687 seconds
drop #删除表
disable 'tb_a2'drop 'tb_a2'
drop_all,
disable_alldrop_all
exists, 查看表是否存在
hbase(main):036:0> exists 'tb_a1'Table tb_a1 does existTook 0.0096 seconds=> true
get_table 类似于别名
t_user = get_table 'tb_ods_app_wx_user'
is_disabled, 是否是禁用状态
is_enabled, 是否是启用状态
hbase(main):014:0> is_disabled 'tb_a1'true Took 0.0108 secondshbase(main):016:0> is_enabled 'tb_a2'true
list查看系统中所有的表
list 'doit24:.*' -- 查看指定名称空间下的表
list_regions — 查看表的所有的region信息


表如何才能有多个region呢?
- 表的数据行数达到阈值, region会自动的拆分
- 手动的强制拆分 / 指定切割点

split 'tb_name' , 'rk003'list_regions 'tb_name'
locate_region 查看key所在的region的位置信息
locate_region 'tb_a1' , 'rk003'HOST REGIONlinux03:16020 {ENCODED => c1a08f08a64dd91da77c5bf97e4f6dd3, NAME => 'tb_a1,rk003,1625192839094.c1a08f08a64dd91da77c5bf97e4f6dd3.', STARTKEY => 'rk003', ENDKEY => ''}1 row(s)c1a08f08a64dd91da77c5bf97e4f6dd3 -- REGION文件夹
show_filters能实现 where 条件查询 但是性能很低
scan 'tb_a1', {FILTER => "ValueFilter (=, 'binary:zss')"} -- 获取值是zss的数据scan 'tb_a1', {ROWPREFIXFILTER => 'rk00'} rk00开头的行数据DependentColumnFilterKeyOnlyFilterColumnCountGetFilterSingleColumnValueFilterPrefixFilterSingleColumnValueExcludeFilterFirstKeyOnlyFilterColumnRangeFilterColumnValueFilterTimestampsFilterFamilyFilterQualifierFilter 属性ColumnPrefixFilterRowFilter 行键MultipleColumnPrefixFilterInclusiveStopFilterPageFilterValueFilter 值
2.2 DML
append 追加 在已有的单元格的后面添加子串
append 'tb_a1' , 'a0001' , 'cf1:name' , '_abc'a0001 column=cf1:name, timestamp=1625195924514, value=zss 前a0001 column=cf1:name, timestamp=1625195924514, value=zss_abc 后-- 如果单元格不存在 , 创建新的单元格 类似于put操作hbase(main):012:0> append 'tb_a1' , 'a0002' , 'cf1:name' , '_abc'CURRENT VALUE = _abcTook 0.0134 seconds
count, 统计表数据行数
hbase(main):014:0> count 'tb_a1'6 row(s)Took 0.0675 seconds=> 6
delete 只能删除单元格
delete 'tb_a1' , 'a0001' , 'cf1:name'
deleteall 删除整行 ,或者 一个单元格
delete 'tb_a1' , 'a0001' 删除行delete 'tb_a1' , 'a0001' , 'cf1:name' 删除单元格
get获取数据 行为单位 根据rowkey 开发中使用比较多
get 'tb_a1' , 'a0001' 一行get 'tb_a1' , 'a0001' ,'cf1:age' 一个单元格hbase(main):044:0> get 'tb_a1' , 'a0001' ,'cf1:age' , 'cf2:job' 多个单元格COLUMN CELLcf1:age timestamp=1625198011401, value=23 cf2:job timestamp=1625198030308, value=coderget 'tb_a1' , 'rk001' , 'cf2:account'get 'tb_a1' , 'rk001' , {COLUMN=>'cf2:account' , VERSIONS=>2}
incr 增加一个自增的字段 用来计数
incr 'tb_name' , 'rk' , 'cf:col' , 20 初始值incr 'tb_name' , 'rk' , 'cf:col' , 2 累加2incr 'tb_name' , 'rk' , 'cf:col' , 1 累加1
get_counter 获取incr字段的值
get_counter 'tb_a1' , 'rk006' , 'cf1:age'
get_splits 获取表的切割点
hbase(main):026:0> get_splits 'tb_a1'Total number of splits = 2rk003
put 单元格数据进行put操作
每次Put都会进行RPC[网络]请求 , 多次交互 ,效率低
缓存一批写一次 ,减少请求次数
HBASE 是一个分布式数据库 , 存储大量的数据 , 假如我们已经存在了大量的静态数据在HDFS中
[文件] --->MR ---->输出到hbase的表写以hfile的格式
scan 全表检索数据 /臃肿/数据量大 一般不用
truncate ;删除数据 ,删除原来的切割点,region信息/ 仅仅保留表的基本结构 l列族
truncate 'tb_a1'
2 JAVA-API
2.1 添加依赖
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>doit24_hbase</artifactId><version>1.0-SNAPSHOT</version><!--JDK的版本--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!--zookeeper--><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.6</version></dependency><!--hadoop--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-auth</artifactId><version>3.1.1</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.1</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.1.1</version></dependency><!-- HBASE依赖 --><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.2.5</version></dependency><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-server</artifactId><version>2.2.5</version></dependency><!-- 使用mr程序操作hbase 数据的导入 --><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-mapreduce</artifactId><version>2.2.5</version></dependency><!--json解析--><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.5.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>2.6</version><configuration><!-- get all project dependencies --><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><!-- MainClass in mainfest make a executable jar --><archive><manifest><!--<mainClass>util.Microseer</mainClass> --></manifest></archive></configuration><executions><execution><id>make-assembly</id><!-- bind to the packaging phase --><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build></project>
2.2 入门示例1
package com._51doit.hbase.day02;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.HBaseConfiguration;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.Admin;import org.apache.hadoop.hbase.client.Connection;import org.apache.hadoop.hbase.client.ConnectionFactory;import org.apache.hadoop.hbase.client.Table;import java.io.IOException;/*** Author: Hang.Z* Date: 21/07/02* Description:* 使用java操作Hbase* 连接zookeeper,获取HBase信息** 1 获取一个连接对象* 2 conn获取Table对象* 3 Table DML有关* get scan put delete incr append* 4 Admin DDL* namespace* tools*/public class Hbase01_Demo {public static void main(String[] args) throws Exception {Configuration conf = HBaseConfiguration.create();// 设置zookeeper的地址conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");// 获取hbase的连接对象Connection conn = ConnectionFactory.createConnection(conf);// 表名TableName tableName = TableName.valueOf("tb_a1");// 表对象Table table = conn.getTable(tableName);Admin admin = conn.getAdmin();// 释放连接conn.close();}}
创建获取连接HBASE的工具类
package doit.day02;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.HBaseConfiguration;import org.apache.hadoop.hbase.client.Connection;import org.apache.hadoop.hbase.client.ConnectionFactory;import java.io.IOException;/*** Author: Hang.Z* Date: 21/07/02* Description:*/public class HbaseUtils {/*** 获取hbase的连接对象* @return* @throws Exception*/public static Connection getConnection() throws Exception {Configuration conf = HBaseConfiguration.create();// 设置zookeeper的地址conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");// 获取hbase的连接对象Connection conn = ConnectionFactory.createConnection(conf);return conn ;}}
2.3 获取所有的名称空间/所有的表
package com._51doit.hbase.day02;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.hbase.HBaseConfiguration;import org.apache.hadoop.hbase.NamespaceDescriptor;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.Admin;import org.apache.hadoop.hbase.client.Connection;import org.apache.hadoop.hbase.client.ConnectionFactory;/*** Author: Hang.Z* Date: 21/07/02* Description:* 1 list 命令* 获取系统中所有的表名* 2 获取所有的namespace*/public class Hbase02_Demo2 {public static void main(String[] args) throws Exception{Configuration conf = HBaseConfiguration.create();conf.set("hbase.zookeeper.quorum","linux01:2181,linux02:2181,linux03:2181");Connection conn = ConnectionFactory.createConnection(conf);Admin admin = conn.getAdmin();// 获取所有的名称空间NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {String name = namespaceDescriptor.getName();System.out.println(name);}// admin 获取所有的表TableName[] tableNames = admin.listTableNames();// 遍历for (TableName tableName : tableNames) {// 获取表名 字节数组byte[] name = tableName.getName();// 封装String打印结果// System.out.println(new String(name));}conn.close();}}
2.4 建表(一个列族)
package doit.day02;import org.apache.hadoop.hbase.HTableDescriptor;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.*;/*** Author: Hang.Z* Date: 21/07/02* Description:* 建表:表名:至少一个列族* create tb_name , cf* 建表 createTable(tableDescriptor);* 参数 表的描述器* 构建器 --> 构建* 1 表的描述器构建器* ---添加列族描述器* 2 build 表的描述器* 1 列族描述器构建器* 2 build 列族描述器*/public class Hbase03_CreateTable01 {public static void main(String[] args) throws Exception {Connection conn = HbaseUtils.getConnection();Admin admin = conn.getAdmin();/*** 表的描述器构建器* 描述器构建器 构建表的描述器* 列族描述器构建器* 构建列族描述器* TableDescriptor*/TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(TableName.valueOf("tb_user"));// 列族描述器构建器ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder("cf".getBytes());ColumnFamilyDescriptor familyDescriptor = columnFamilyDescriptorBuilder.build();// 将列族描述器 添加到表中tableDescriptorBuilder.setColumnFamily(familyDescriptor) ;// 构建表描述器TableDescriptor tableDescriptor = tableDescriptorBuilder.build();// 建表admin.createTable(tableDescriptor);conn.close();}}
2.5 建表(多列族)
package doit.day02;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.*;import java.util.ArrayList;import java.util.List;/*** Author: Hang.Z* Date: 21/07/02* Description:* 创建多列族的表*/public class Hbase04_CreateTable02 {public static void main(String[] args) throws Exception {Connection conn = HbaseUtils.getConnection();Admin admin = conn.getAdmin();// 表的描述器构建器TableDescriptorBuilder tbbuild = TableDescriptorBuilder.newBuilder(TableName.valueOf("tb_teacher"));// 列族的描述器构建器 cf1ColumnFamilyDescriptorBuilder cf1Build = ColumnFamilyDescriptorBuilder.newBuilder("cf1".getBytes());// 构建表述器ColumnFamilyDescriptor cf1 = cf1Build.build();// 列族的描述器构建器 cf2ColumnFamilyDescriptorBuilder cf2Build = ColumnFamilyDescriptorBuilder.newBuilder("cf2".getBytes());// 构建表述器ColumnFamilyDescriptor cf2 = cf2Build.build();// 列族的描述器存入集合List<ColumnFamilyDescriptor> cfs = new ArrayList<>() ;cfs.add(cf1);cfs.add(cf2);tbbuild.setColumnFamilies(cfs);//构建表的描述器TableDescriptor tableDescriptor = tbbuild.build();admin.createTable(tableDescriptor);admin.close();conn.close();}}
2.6 建表(多列族,并且设置列族属性)
package doit.day02;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.*;import java.util.ArrayList;import java.util.List;/*** Author: Hang.Z* Date: 21/07/02* Description:* 创建多列族的表,设置他们的属性*/public class Hbase05_CreateTable03 {public static void main(String[] args) throws Exception {Connection conn = HbaseUtils.getConnection();Admin admin = conn.getAdmin();// 表的描述器构建器TableDescriptorBuilder tbbuild = TableDescriptorBuilder.newBuilder(TableName.valueOf("tb_teacher2"));// 列族的描述器构建器ColumnFamilyDescriptorBuilder cf1Build = ColumnFamilyDescriptorBuilder.newBuilder("cf1".getBytes());/*** 设置当前列族的参数*/cf1Build.setMaxVersions(3) ;// 构建表述器ColumnFamilyDescriptor cf1 = cf1Build.build();// 列族的描述器构建器ColumnFamilyDescriptorBuilder cf2Build = ColumnFamilyDescriptorBuilder.newBuilder("cf2".getBytes());/*** 设置当前列族的参数* 设置列族数据的过期时间 单位 s 妙*/cf2Build.setTimeToLive(240) ;// 构建表述器ColumnFamilyDescriptor cf2 = cf2Build.build();// 设置多个列族List<ColumnFamilyDescriptor> cfs = new ArrayList<>() ;cfs.add(cf1);cfs.add(cf2);tbbuild.setColumnFamilies(cfs);//构建描述器TableDescriptor tableDescriptor = tbbuild.build();admin.createTable(tableDescriptor);admin.close();conn.close();}}
2.7 创建预分region表
package doit.day02;import org.apache.hadoop.hbase.TableName;import org.apache.hadoop.hbase.client.*;import java.util.ArrayList;import java.util.List;/*** Author: Hang.Z* Date: 21/07/02* Description:* 创建预分region表*/public class Hbase06_CreatePreRegionTable04 {public static void main(String[] args) throws Exception {Connection conn = HbaseUtils.getConnection();Admin admin = conn.getAdmin();// 表的描述器构建器TableDescriptorBuilder tbbuild = TableDescriptorBuilder.newBuilder(TableName.valueOf("tb_pre_region2"));// 列族的描述器构建器ColumnFamilyDescriptorBuilder cf1Build = ColumnFamilyDescriptorBuilder.newBuilder("cf1".getBytes());/*** 设置当前列族的参数*/cf1Build.setMaxVersions(3) ;// 构建表述器ColumnFamilyDescriptor cf1 = cf1Build.build();// 列族的描述器构建器ColumnFamilyDescriptorBuilder cf2Build = ColumnFamilyDescriptorBuilder.newBuilder("cf2".getBytes());/*** 设置当前列族的参数* 设置列族数据的过期时间 单位 s 妙*/cf2Build.setTimeToLive(240) ;// 构建表述器ColumnFamilyDescriptor cf2 = cf2Build.build();// 设置多个列族List<ColumnFamilyDescriptor> cfs = new ArrayList<>() ;cfs.add(cf1);cfs.add(cf2);tbbuild.setColumnFamilies(cfs);//构建描述器TableDescriptor tableDescriptor = tbbuild.build();/*** 参数一* 参数二 , 分割点 在hbase中所有数据都是字节数组* a.getBytes()* [a.getBytes(),o.getBytes()]* a0001* z001*/byte[][] keys = new byte[][]{"f".getBytes(),"o".getBytes(),"x".getBytes()} ;admin.createTable(tableDescriptor , keys);admin.close();conn.close();}}
3 热点问题
问题描述,HBASE在数据量很小的时候,默认只会为数据分配一个region,随着数据量的增多,越来越多的数据存储在同一台机器,而不是分布在多台机器上,此时查询速度就会变慢,插入数据也会变慢。这就是热点问题。

解决方案:
在创建表的时候,指定切割点,手动将表分为多个region,将数据根据切割点合理的分配在不同的节点上。

shell端
create 'tb_pre_region' , 'cf' , SPLITS=>['f','o','x']
Java端
byte[][] keys = new byte[][]{"f".getBytes(),"o".getBytes(),"x".getBytes()} admin.createTable(tableDescriptor , keys);
