Hbase入门到实操

一、Hbase的概述

1.1 Hbase的简介

1)简要介绍

1. Hbase是一个Hadoop 数据库
2. 是一个非关系型(NoSql:Not Only SQL)的、分布式的、具有良好的扩展性、面向列式存储的数据库。
3. 开发灵感来源于Google的Bigtable论文,java语言编写,并且开源。

2)特性

- 强一致性读/写:具有一致性读和写的功能,适合统计分析聚合类型的任务.
- 自动分片:hbase的表对应的region会根据大小自动拆分,并重写分布
- 自动 RegionServer故障转移
- Hbase的存储是基于HDFS的
- hbase可以和Mapreduce进行整合,从而进行数据分析
- Hbase还提供了java语言的客户端接口
- Thrift/REST API:Hbase也提供了非java语言的连接操作
- Hbase提供了块缓存和布隆过滤器等机制来提高查询效率等

3)何时选择Hbas

1. 当数据量特别大的时候,
2. 集群节点数多于10个的情况下。
3. 以及不需要具有事务、高级查询语言等功能的情况下。

1.2 Hbase的表模型(重点)

1.2.1 关系型数据库的表模型

1. 表模型是面向行式存储的。也就是每一条记录的数据都是紧凑的挨着的。
2. 优点:
	 -- 用户在插入数据时,效率特别高,只是追加操作。
	 -- 在查询操作时,比如select * 时效率是非常高的
	 -- 结构清晰,每一行的列的数量是固定的
	 -- 支持ACID事务
3. 缺点:
    -- 一旦数据表中存储数据后,修改表结构变得特别困难。
	 -- 如果我们想扩展字段时,会对表结构产生影响。
    -- 即使某一行中的某个字段没有赋值,也要使用null填充
    -- 一旦涉及到多张表,因为数据表存在着复杂的关系,管理非常不方便。	  比如外键约束
    -- 一旦面对海量数据的处理时,读写性能特别差,尤其在高并发这一块。

1.2.2 Hbase的表模型(重点)

1、 hbase是面向列(colum family:列簇,列族)式存储的。
2. 定义表的时候不需要指定列名,列类型。只需要指定列族名即可
3. 数据实际上是按照key:value形式存储的,一个kv对通常称之为一个Cell(单元格)
4. 每个kv对后都有一个版本号。版本号是一个时间戳。一个K可以有多个版本
5. 为了方便管理多个KV对,引入了列族的概念。
   -- 一个列族对应至少一个文件
   -- 列族之间一定是不同的文件
6. 又为了区分KV是不同的事物的,引入了rowkey的概念。 因此rowkey必须具有唯一性
7. 为了管理表的数据,引入了region的概念。一个region对应一张表,或者是一张表的一部分。
   region是由rowkey的范围来表示的。
   
        如果一张表只有一个region:   
        region的rowkey的偏移量:startKey没有最小值,endKey也没有最大值。
8. Hbase的中的所有数据,都是byte[]类型。没有其他类型
9. hbase会在内存里进行排序:
       查询时:先按照rowkey排序,然后是列族名排序,再按照key进行排序
       实际上插入数据时:   先按照rowkey进行排序,再按照key进行排序         都是字典排序规则

1.3 Hbase的体系架构(重点)

1. Client:hbase的客户端
	- hbase提供了客户端使用的API接口
   - API里还维护了一个缓存机制,用于加快客户端访问的效率,比如缓存查询过的region的地址
2. Zookeeper
	- 维护hbase的高可用,保证只有一个活跃的Hmaster,其他的为backup
	- 维护着regionserver的动态上下线感知
	- 维护着所有的region地址以及部分元数据
3. Hmaster
	- hmaster主要管理着region的负载均衡
		   (1) 表的第一个region分配的位置
		   (2) region过大后,进行切分后,形成的新region的重新分配
		   (3) regionserver宕机后的region的重新分配
	- hdfs上的垃圾回收
   - 处理新的schama的维护(namespace的创建和删除等)
4. RegionServer
	- 主要就是管理本节点上的所有region(包括region的切分)。
	- 处理客户端的读写请求
	- 负责hlog和storefile的读和写
5. Region
	- 实际上就是表,或者是表的一部分。    是Hbase的表的存储单元 
	- 本质:在hdfs上是目录
6. store
   - 一个列族对应一个store      
   - 本质:在是region目录下的子目录。
7. memstore
	- 一个store 对应一个memstore(写缓存),默认大小是128M. 
8. Hfile/StoreFile
   - 当memstore达到阈值(128M,1小时,或者是内存的40%)就会被flush出来,形成一个storefile。以hfile存储格式存储到HDFS上。
9. hlog:
   - 一个regionserver上维护着一个hlog文件。以WAL(write ahead log)格式记录着客户端的操作,防止宕机后丢失数据,然后可以重演一次,以便找回数据。

二、Hbase的安装

2.1 单机模式的简要说明(了解)

就是在一台节点上,解压,配置环境变量,启动一个hmaster服务,没有regionserver服务项,使用本地的文件系统存储数据。

2.2 伪分布式的搭建(了解)

伪分布式,指的是除了有hmaster外,只有一个regionserver服务项。存储的文件系统可以是本地文件系统,也可以使用hdfs。

2.3 完全分布式的搭建(重点)

2.3.1 简要说明

完全分布式,指的就是除了hmaster守护进程外,有多个regionserver守护进程,并且每一个regionserver守护进程独占一个机器节点。使用的文件系统是HDFS。

布局如下:

qianfeng01:  hmaster   regionserver
qianfeng02:  hmaster   regionserver
qianfeng03:            regionserver

环境说明:

必须配置好集群的免密登录认证
必须配置时间同步。保证集群节点的时间差不能超过30秒,否则regionserver启动失败

2.3.2 搭建步骤

步骤1): 上传、解压、配置环境变量 、重导生效

[root@qianfeng01 ~]# tar -zxvf hbase-1.2.1-bin.tar.gz -C /usr/local/
[root@qianfeng01 ~]# cd /usr/local/
[root@qianfeng01 local]# mv hbase-1.2.1/ hbase
[root@qianfeng01 local]# vim /etc/profile
.......省略.......
#hbase environment
export HBASE_HOME=/usr/local/hbase
export PATH=$HBASE_HOME/bin:$PATH

[root@qianfeng01 local]# source /etc/profile

步骤2):配置hbase-env.sh环境脚本

[root@qianfeng01 local]# vi $HBASE_HOME/conf/hbase-env.sh

#找到下面内容,解开注释,添加具体路径

# The java implementation to use.  Java 1.7+ required.
export JAVA_HOME=/usr/local/jdk

# Tell HBase whether it should manage it's own instance of Zookeeper or not.
export HBASE_MANAGES_ZK=false       #禁止内置zookeeper

步骤3):配置hbase-site.xml文件

<configuration>
   <!-- 指定hbase在HDFS上存储的路径 -->
   <property>
      <name>hbase.rootdir</name>
      <value>hdfs://qianfeng01:8020/hbase</value>
   </property>
   <!-- 指定hbase是分布式的 -->
   <property>
      <name>hbase.cluster.distributed</name>
      <value>true</value>
   </property>
   <!-- 指定zk的地址,多个用“,”分割 -->
   <property>
      <name>hbase.zookeeper.quorum</name>
      <value>qianfeng01:2181,qianfeng02:2181,qianfeng03:2181</value>
   </property>
   <!--将属性hbase.unsafe.stream.capability.enforce 改为true -->
   <property>
      <name>hbase.unsafe.stream.capability.enforce</name>
      <value>true</value>
   </property>
   <!-- 取消内存检查 -->
   <property>
      <name>hbase.table.sanity.checks</name>
      <value>false</value>
   </property>
</configuration>

步骤4):配置regionservers文件,添加regionserver所在机器的host

[root@qianfeng01 local]#  vi $HBASE_HOME/conf/regionservers

删除localhost
添加:
	qianfeng01
    qianfeng02
    qianfeng03

步骤5):配置备份hmaster: 创建backup-masters文件

[root@qianfeng01 local]#  cd $HBASE_HOME/conf/
[root@qianfeng01 conf]#  echo "qianfeng02">> backup-masters

步骤6): 将hadoop的core-site.xml和hdfs-site.xml拷贝到hbase的conf目录下

[root@qianfeng01 conf]#  
cp $HADOOP_HOME/etc/hadoop/{
    
    core-site.xml,hdfs-site.xml} $HBASE_HOME/conf/

步骤7):同步到其他节点上

[root@qianfeng01 local]# scp -r /usr/local/hbase qianfeng02:/usr/local
[root@qianfeng01 local]# scp -r /usr/local/hbase qianfeng03:/usr/local
[root@qianfeng01 local]# scp /etc/profile qianfeng02:/etc/
[root@qianfeng01 local]# scp /etc/profile qianfeng03:/etc/

注意:
     重新引导一下各个节点的环境变量配置情况

2.3.3 启动集群

启动顺序如下:

第一步:必须先启动hdfs和zookeeper

[root@qianfeng01 ~]# zkServer.sh start
[root@qianfeng02 ~]# zkServer.sh start
[root@qianfeng03 ~]# zkServer.sh start

别忘记:zkServer.sh status查看状态

[root@qianfeng01 ~]# start-dfs.sh

第二步:启动hbase的守护进程

[root@qianfeng01 ~]# start-hbase.sh

第三步:检查相关进程

方式1: jps
方式2: webui  ---> qianfeng01:16010

2.3.4 客户端连接集群

1)hbase本身自己就提供了一个命令行连接工具

[root@qianfeng01 ~]# hbase shell

2)可以使用java语言调用API接口连接

2.4 Hbase集群的扩展和退役(了解)

2.4.1 扩展节点

1)原理说明

regionserver会主动向zookeeper的某一个节点/hbase/rs下注册一个临时节点, 而master一直在监听这个/hbase/rs, 如果突然多了一个临时节点,zookeeper会通知master,从而master可以进行相关任务的分配。

2)具体操作

参考文档

2.4.2 退役节点

1)原理说明

master一直在监听zookeeper上的这个/hbase/rs, 如果突然少了一个临时节点,zookeeper会通知master,从而master可以进行相关任务的分配。

2)具体操作

参考文档

三、Hbase的shell(熟悉)

hbase(main): > help      查看所有的命令组及其命令 名称
hbase(main): > help 'COMMAND GROUPNAME'  查看命令组里的命令用法
hbase(main): > help 'COMMAND'  查看指定的命令用法

3.1 namespace的DDL

1、列出命名空间: list_namespace

2、创建命名空间: create_namespace

3、描述命名空间: describe_namesapce

4、修改命名空间的属性: alter_namespace

5、删除命名空间:drop_namesapce

3.2 table的DDL

表结构的创建:create

表结构的查看:list、list_namespace_tables、describe

表结构的修改:alter

指的是对列族的增加、或者是列族属性的修改
删除指的就是删除列族。

表结构的删除:disable、disable_all、drop、drop_all

3.3. table的CRUD

表数据的增加:put

表数据的查看:scan、get

表数据的删除:delete,truncate

四、hbase的API(重点)

4.1 namespace的DDL

参考代码、视频、文档

4.2 table的DDL

参考代码、视频、文档

4.3 table的CRUD(重点)

参考代码、视频、文档

4.4 Hbase的Filter(重点)

4.4.1 单列过滤器:SingleColumnValueFilter
4.4.2 结构过滤器:FilterList
4.4.3 列值比较器: 四个
			  正则表达式(可以代替下面三个):
			  子串:
			  二进制:
			  二进制前缀:
4.4.4 KeyValue元数据过滤器
	  --列族过滤器
	  --列名过滤器   select
	  --列名前缀过滤器
	  --多列名前缀
	  --列名范围过滤器   
4.4.5 RowKey过滤器
	  RowFilter
4.4.6 Utility过滤器
	  FirstKeyOnlyFilter
4.4.7 分页过滤器
      PageFilter

五、Hbase的工作机制(重点)

5.1 Hbase的寻址机制(重点)

1.   table.put()      put 'myns:student'
     table.get()/getScanner()      get/scan....
     
     put 'myns:student', 'rk01000', 'f1:name'
       
       
     region:  startkey,   endkey
     
-- zookeeper:  维护了meta表的信息,就是地址
               get /hbase/meta-region-server
-- hbase:meta表:    记录了所有表的所有的region信息
                每个region以四个单元格进行记录,单元格的rowkey,就是region的名称
                四个单元格中的两个单元格:
                info:regioninfo维护的是region的名称,以及行范围
                info:server维护的region的位置
                
                region名称: schema:tablename,startkey,timestamp.ENCODED

在这里插入图片描述

5.2 Hbase的存储机制(重中之重)

5.2.1 存储机制介绍

1.  通过寻址流程定位到具体的region。
2. 将单元格存储到store对应的memstore中
3. 排序:按照rowkey进行升序,key进行升序,timestamp降序
        单元格数据格式如下:  
        rowkey:column family:column:value:timestamp
        
4. 达到flush的阈值时,开始flush,生成storefile.然后由store来维护n个storefile的索引信息,比如path,startkey,endkey
      
      flush阈值: 128M、 1小时、  当前region内存的40%  、当前regionserver内存40%
      
5. 当storefile的数量达到阈值,比如是3个。就进行合并。  合并期间会进行排序(rowkey升序,column升序,timetamp降序),  还会进行真正的删除(当发现有delete标记的单元格,就将所有版本过滤掉)和修改操作(超过版本数量的老版本过滤掉)6. 当合并的文件越来越大时,如果达到阈值(10G),就会触发split操作,数据尽量做到均分(会影响其他文件的切分),从而造成了region的切分。  旧region下线,两个的新的region维护数据,由hmaster来重新进行负载均衡。        

5.2.2 名词解释

  • flush

    当memstore达到阈值是,将内存中的数据冲刷成文件
    
    可以手动flush
    查看用法:  help 'flush'
    
  • compact

    当storefile达到数量阈值时,进行合并操作。
    
    手动合并:
    major_compact  regionname
    
  • split

    当文件大小达到阈值时,会造成region的切分
    手动切分:
    split regionname,splitkey
    

5.3 Hbase的Region管理

1)预切分

建表期间,进行预切分,指的就是提前划分region。
create tablename,column family,SPLITS=>[startkey1,startkey2....] 
region数量 = startkey的数量+1

2)当文件达到阈值时,会主动切分

split regionname,splitkey

3)region也可以合并

merge_region  'encoded_region','encoded_region'

5.4 Hbase的读写流程(重点)

5.4.1 Hbase的读流程

1.  客户端请求zookeeper,获取meta表的位置信息
2.  客户端跳转到meta表,获取要访问的表的具体region位置
3.  客户端跳转到具体region所在的regionserver,找到该region。
4.  访问对应的store下的memstore(写缓存), 如果有数据就返回,如果没有数据,就访问regionserver对应的读缓存,如果没有数据,再访问磁盘,然后数据返回给客户端,并保存到读缓存中,方便下次快速读取。

5.4.2 Hbase的写流程

1.  客户端请求zookeeper,获取meta表的位置信息
2.  客户端跳转到meta表,获取要访问的表的具体region位置
3.  客户端跳转到具体region所在的regionserver,找到该region,将单元格写入到对应的store里的memstore
4.  在memstore里进行排序(按照rowkey进行升序,key进行升序,timestamp降序)
5.  如果达到memstore的阈值,就会flush成storefile文件,由store来维护该文件的索引信息。
6.  如果storefile数量达到阈值是,会进行合并操作(排序,实际的删除和修改)
7.  如果合并成的文件达到大小阈值时,会进行切分,造成region的切分(旧region下线,两个新region生成)

5.5 布隆过滤器(面试题)

5.5.1 简介

- 布隆过滤器是一个数据结构
- 内部维护着一个二进制向量的位数组,默认大小64K
- 还维护着N个hash算法, 默认值是3个。
- 牺牲了准确率,算法的时间复杂度是O(1)。从而提高了查询效率
- 特点:  判断一个元素是否在一个集合中,有两种结果:一种就是在集合中,但是不一定真实存在
         另外一种结果就是不在集合中,那么就一定不在集合中。

5.5.2 原理

当存储元素时,会调用hash算法,计算元素的三个hash值,三个值作为bit数组的下标,将对应的元素由0改为1. (注意,hbase在put数据,不判断是否存在过)。

当在查询一个元素是否在这个集合中时,也是算出三个hash值作为下标,访问对应上的数据是否为1,如果全都是1,表明该元素可能存在这个集合中。只要有一个位置上是0,则表示该元素一定不在集合中。 

在这里插入图片描述

5.5.3 Hbase中的布隆过滤器的设置

方法:columnfamily.setBloomFilterType()
布隆过滤器的级别:
  BloomType.NONE:    表示不启用布隆过滤器
  BloomType.ROW:     行级别的,  只对每一个rowkey做 布隆过滤器的数据存储
  BloomType.ROWCOL:  行列级别的, 对rowkey:columnfamily:column做布隆过滤器的数据存储
  
  
  参考文档上的布隆过滤器章节的作用:

六、Hbase与Hive、Mapreduce的整合

6.1 Hbase与Hive的整合

6.1.1 为什么要整合

hbase: hadoop数据库,本质用来存储大数据集,虽然提供了近似实时的读写功能
hive:  数据仓库的管理工具,作用就是用来使用hql语言对数据进行分析。

6.1.2 Hive-to-hbase

在hive创建表, 可以在hbase中看见
create table if not exists employee (
uid int,
uname string,
age int,
sex string,
province string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,base_info:name,base_info:age,base_info:sex,address:provice"
)
tblproperties(
"hbase.table.name"="myns:employee"
);

动态加载数据

insert into employee values(1, 'michael', 32, '男','jilin');
insert into employee values(2,'wcm',23,'男','heilongjiang');
put 'myns:employee','3','base_info:name','lisi'

结果查看

- 在hive中写一个select语句
- 在50070webui上查看hive下的表目录,  结论:没有数据, hive不负责存储
- 在hbase中写一个scan语句
- 在50070webui上查看hbase下的表目录,  结论:应该有数据,如果看不到,是因为还在内存中

6.1.3 Hbase-to-Hive

hbase中先有表,然后映射到hive中
create 'myns:student','f1','f2'

put 'myns:student','rk00001','f1:name','zhaoyun'
put 'myns:student','rk00001','f1:age',23
put 'myns:student','rk00001','f1:gender','m'
put 'myns:student','rk00002','f1:name','zhenji'
put 'myns:student','rk00002','f1:age',24
put 'myns:student','rk00002','f2:province','hebei'

在hive中创建表与hbase中的表进行映射

drop table student;
create external table if not exists student (
sid string,
name string,
province string,
gender string,
age int
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,f1:name,f2:province,f1:gender,f1:age"
)
tblproperties(
"hbase.table.name"="myns:student"
);

结果查看

在hive中 写select语句进行查看。

6.1.4 总结

-1.hive表的字段与hbase表的单元格 是按照顺序映射,而不是根据名称映射。
-2.hbase的rowkey 可以映射成hive中的一个字段,通过:key进行映射。可以不写:key,则与hive的第一个字段映射
-3.在字段映射时,注意字段类型的合理性
-4.如果hbase表已经存在,进行hive新表映射,hive表必须是外部表。

七、Hbase的二级索引和协处理器

7.1 二级索引的简介

rk1001     f1:name-zhangsan      f1:age-23           f2:province-guangdong
........................
rk2001     f1:name-gaoyuanyuan      f1:age-38        f2:province-shanghai
...........
rk3001     f1:name-gaoyuanyuan


需求:  查询 name叫gaoyuanyuan的年龄

    SingleColumnValueFilter---    name:gaoyuanyuan
    
    hbase的底层逻辑: 遍历数据块中的所有行信息,要查看是否有name:gaoyuanyuan单元格,有,返回所有行。
           程序员需要再次编程对返回的所有行数据,查看是否age单元格。有,就返回。 性能很低。
           
           
如何提高上述需求类型的查询性能???  再维护一张表:单元格与rowkey的映射关系表。

index表:
rowkey:
.........
f1:name-gaoyuanyuan     info:rk1  'rk2001'
                        info:rk2  'rk3001'
......
f1:name-zhangsan        info:rk1  'rk1001'
........


什么是二级索引表

概念:维护的数据是另外一张表的单元格与rowkey的映射关系的表,就是二级索引表
作用:提高查询效率,避免对原表的全表遍历, 牺牲磁盘空间,换取查询效率。

小贴士:

二级索引表,应该是程序自动维护的。

7.2 协处理器组件简介

7.2.1 为什么要引入协处理器

在Hbase的低版本(0.92以前)作为列族数据库最经常被人诟病的特性包括:无法轻易建立“二级索引”,难以执行求和、计数、排序等操作。
之后引入了协处理器(coprocessor)进行改进,可以轻松的实现上述需求。

7.2.2 协处理器的分类(熟悉)

分两大类型:一个是Observer类型, 一个是endpoint类型

- Observer 允许集群在正常的客户端操作过程中可以有不同的行为表现  
- Observer 类似于 RDBMS 中的触发器,主要在服务端工作
- Observer 可以实现权限管理、优先级设置、监控、ddl 控制、二级索引等功能

- Endpoint 类似于 RDBMS 中的存储过程,主要在服务端工作
- Endpoint 允许扩展集群的能力,对客户端应用开放新的运算命令  
- Endpoint 可以实现 min、max、avg、sum、distinct、group by 等功能

7.2.3 协处理器的加载和卸载

1)加载方式:两种

第一种:静态加载,也叫系统级别的协处理器,只需要在hhbase-site.xml里添加如下属性和具体类名

<property>
   <name>hbase.coprocessor.user.region.classes</name>
   <value>类全名</value>
</property>

可以用”,”分割加载多个 class

第二种:动态记载,称之为表级别的协处理器

只对特定的表生效。通过 HBase Shell 来实现。

1. 停用表  disable 'mytable'

2. 添加协处理器  
alter 't_guanzhu',METHOD => 'table_att',
'coprocessor'=>
'hdfs://supercluster/jar/mycoprocessor.jar|com.qf.hbase.coprocessor.MyIndexCoprocessor|1001|'
3. 启用表  enable 'mytable'

2)卸载方式

1. disable 'mytable'
2. alter 'mytable',METHOD=>'table_att_unset',NAME=>'coprocessor$1'
3. enable 'mytable'

3)注意事项:

如果写的协处理器逻辑有问题,那么可能会造成hbase的集群宕机

解决办法:
1. 关闭所有的hbase的守护进程
2. 进入zookeeper,删除相关的znode。  如果不知道是哪一个znode,就将hbase 整个删掉
3. 重新启动hbase,删除掉挂载了协处理器的那张表。重新维护表
4. 再加载协处理器,进行测试

7.3 案例演示:使用协处理器完成二级索引表的创建

7.3.1 案例描述

模拟博客上的关注信息表,以及粉丝表。 
1. 关注信息表是原表: 维护的是每个用户关注的人
      rk0001     f1:user-wcm    f1:obj-gaoyuanyuan    ......
      ......
      rk0009     f1:user-wcm    f1:obj-canglaoshi     .....
      ....
      rk0019     f1:user-laoli  f1:liuyifei
    
2. 粉丝表是二级索引表。
   
		wcm-gaoyuanyuan      f1:rk-rk0001
		wcm-canglaoshi       f1:rk-rk0009
		...........
		laoli-gaoyuanyuan    f1:rk-rk0019
		
create 'fans','f1'		

7.3.2 代码编写

package com.qf.hbase.coprocessor;

import com.qf.hbase.util.HbaseUtil;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;

import java.io.IOException;
import java.util.List;

public class FansObServer extends BaseRegionObserver {
    
    
    /**
     * 重写prePut方法。
     * @param e
     * @param put    put形参就会主动接受客户端提交的put对象
     * @param edit
     * @param durability
     * @throws IOException
     *
     *      rk0001     f1:user-wcm    f1:obj-gaoyuanyuan
     *
     *
     *      注意:该Observer是对原表进行监听
     */
    @Override
    public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
    
    
        //获取put对象上的rowkey
        byte[] row = put.getRow();
        String rowkey = new String(row);  //rk0001
        List<Cell> users = put.get("f1".getBytes(), "user".getBytes());
        Cell cell = users.get(0);
        String value = new String(CellUtil.cloneValue(cell));  //wcm

        List<Cell> objs = put.get("f1".getBytes(), "obj".getBytes());
        Cell cell2 = objs.get(0);
        String value1 = new String(CellUtil.cloneValue(cell2));  //gaoyuanyuan

        //先封装一个新的put对象,准备提交到Fans表中   wcm-gaoyuanyuan      f1:rk-rk0001
        Put newPut = new Put((value+"-"+value1).getBytes());
        newPut.addColumn("f1".getBytes(),"rk".getBytes(),rowkey.getBytes());

        Table table = HbaseUtil.getTable("Fans");  //千万别写错表名
        table.put(newPut);
        table.close();

    }
}

7.3.3 动态加载协处理器

--1. 创建关注表
create 'guanzhu','f1'

--2. 加载协处理器
     (1)先将jar包上传到hdfs上的/jar目录下
     (2)挂载
alter 'guanzhu',METHOD => 'table_att','coprocessor'=>'hdfs://qianfeng01/jar/sz2103_hbase.jar|com.qf.hbase.coprocessor.FansObServer|1001|'

7.3.4 案例测试

小贴士:基于案例的需求,user和obj单元格应该同时添加,所以,应该使用api添加数据

@Before
public void getTable(){
    
    
   table = HbaseUtil.getTable("guanzhu");
}
@Test
public void putOne() throws IOException {
    
    
   //1. 获取Put对象,指定rowkey
   Put put = new Put(Bytes.toBytes("rk0001"));
   //2. 指定列族名,列名,列值
   put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("user"), Bytes.toBytes("wcm"));
   put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("obj"), Bytes.toBytes("gaoyuanyuan"));
   //3. 提交
   table.put(put);
}

最后查看两张表的信息

hbase(main):009:0> scan 'Fans'
ROW                              COLUMN+CELL
wcm-gaoyuanyuan                  column=f1:rk, timestamp=1640165499598, value=rk0001



hbase(main):010:0> scan 'guanzhu'
ROW                               COLUMN+CELL
 rk0001                           column=f1:obj, timestamp=1640165499610, value=gaoyuanyuan
 rk0001                           column=f1:user, timestamp=1640165499610, value=wcm

八、Hbase的优化

8.1 在设计表上进行优化

1)预分区

在创建表的时候进行预分区,好处是,减少hbase的region的切分所造成的性能开销。

2)优秀的rowkey设计(重要)

热点问题:  当过多的请求集中在某一个机器节点上,可能会造成机器的瘫痪。 这种问题就叫热点问题。
1. rowkey的唯一原则

2. rowkey的长度一致原则
    长度不一致的缺点,排序不是我们所想要的
           1 2 3 ....10....40....101....121....
           上述rowkey不统一长度,排序如下:
           1
           10
           101
           121
           2
           3
           40
           应该统一长度:  001,002,003.....010.....040.....101....121...
     长度:建议低于100个字节, 最好是16个字节。 不过要看具体需求具体分析。     
3. rowkey的散列原则:(避免热点问题)
    -- rowkey的reverse
       136.....72345
       137.....62345
       137......2346
       ..........

       54326.....731
       54327.....631
       6432......731
    -- 加盐Salt  
    -- hash随机
          提前对普通的rowkey进行hash算法或者是取模算法或者其他的加密算法。将计算出来的结果,取前4位,作为前缀,拼接到rowkey前。这样的就可以将数据分散到不同的region里存储了。
          
         942a-abc001  -->     
         3030-abc002

3)列族个数

-- hbase对多于2以上的列族维护性能开销很大
   某一个列族下的一个文件达到大小阈值时,可能会关联到其他文件的切分,就会产生大量的磁盘IO。

4)使用内存

在建表时,可以开启regionserver的缓存。将表缓存到服务端。

5)版本数量与存活周期的设计

根据数据的重要性,适当的调整版本数量和存储周期

6)合并和切分

compact: 减少storefile的数量,可以提高查询效率。因此,可以适当的手动触发合并。
split: hbase的切分会产生性能开销,因此可以调高storefile大小阈值。

8.2 写表操作的优化

1)大数据集多可客户端写

数据量特别大的时候,可以使用多个Table进行写操作

2)取消自动flush

客户端有缓存,默认情况下是一条一flush,取消后,可以批量的put
HTable.setAutoFlush(false)

3)提高客户端的buffer

可以提高客户端的缓存字节数,批量的冲刷
table.setWriteBufferSize();
参数: hbase.client.write.buffer

4)取消WAL写(谨慎使用)

在配置文件中设置HLog的是否写操作。hbase-site.xml

5)批量put

默认情况下是一条一put。  可以使用put(List<put> puts)

6)多线程写

并发的写

8.3 读表操作的优化

1)大数据集多客户端读

数据量特别大的时候,可以使用for循环开启多个Table读数据

2)参数设置

可以设置客户端,以及服务端的相关参数:
hbase.client.scanner.caching : 设置一次scan的条数, 默认是1条, 可以往大了调整。 减少scan与hbase的交互次数

3)批量读取

get(List<Get> gets)

4)多线程读取

并发读取

5)客户端设置缓存

可以自己写api, 在程序中维护一个数据结构,来存储查询过的数据。前提是这样的数据要频繁查询多次。

6)提高服务端的读缓存

8.4 其他相关优化

1)hdfs

2)zookeeper

3)linux

4)hbase高可用

启动高可用,多个hmaster.     hmaster可以有多个

5)关闭不必要的服务

节省内存使用资源

整版本数量和存储周期


6)合并和切分

compact: 减少storefile的数量,可以提高查询效率。因此,可以适当的手动触发合并。
split: hbase的切分会产生性能开销,因此可以调高storefile大小阈值。


## 8.2 写表操作的优化

1)大数据集多可客户端写

数据量特别大的时候,可以使用多个Table进行写操作


2)取消自动flush

客户端有缓存,默认情况下是一条一flush,取消后,可以批量的put
HTable.setAutoFlush(false)


3)提高客户端的buffer

可以提高客户端的缓存字节数,批量的冲刷
table.setWriteBufferSize();
参数: hbase.client.write.buffer


4)取消WAL写(谨慎使用)

在配置文件中设置HLog的是否写操作。hbase-site.xml


5)批量put

默认情况下是一条一put。 可以使用put(List puts)


6)多线程写

并发的写


## 8.3 读表操作的优化

1)大数据集多客户端读

数据量特别大的时候,可以使用for循环开启多个Table读数据


2)参数设置

可以设置客户端,以及服务端的相关参数:
hbase.client.scanner.caching : 设置一次scan的条数, 默认是1条, 可以往大了调整。 减少scan与hbase的交互次数


3)批量读取

get(List gets)


4)多线程读取

并发读取


5)客户端设置缓存

可以自己写api, 在程序中维护一个数据结构,来存储查询过的数据。前提是这样的数据要频繁查询多次。


6)提高服务端的读缓存

## 8.4 其他相关优化

1)hdfs

2)zookeeper

3)linux

4)hbase高可用

启动高可用,多个hmaster. hmaster可以有多个


5)关闭不必要的服务

节省内存使用资源


猜你喜欢

转载自blog.csdn.net/weixin_45682261/article/details/125117535
今日推荐