大数据技术之HBase系统知识整理(从安装到熟练操作)

一、HBase简介

1.1 HBase定义

  HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库

1.2 HBase数据模型

  逻辑上,HBase的数据模型同关系型数据库很类似,数据存储在一张表中,有行有列。但从HBase的底层存储物理存储结构(K-V)来看,HBase跟像是一个multi-dimensional map

1.2.1 HBase逻辑结构

在这里插入图片描述

1.2.2 HBase物理存储结构

在这里插入图片描述

1.2.3 数据模型

  1. Name Space
      命名空间,类似于关系型数据库的DataBase概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是Hbase和default,hbase中存放是的HBase内置的表
  2. Region
      类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往HBase写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase能够轻松应对字段变更的场景
  3. Row
      HBase表中的每行数据都由一个RowKey和多个Column(列)组成,数据是按照RowKey的字典顺序存储的,并且查询数据时只能根据RowKey进行检索,所以RowKey的设计十分重要
  4. Column
      HBase中的每个列都由Column Family(列族)和Column Qualifier(列限定符)进行限定,例如info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义
  5. Time Stamp
      用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入HBase的时间
  6. Cell
      由{rowkey,column Family:column Qualifier,time Stamp}唯一确定的单元。cell中的数据是没有类型的,全都是字节码形式存贮

1.3 HBase基本架构

在这里插入图片描述
架构角色:

  1. Region Server
    Region Server为Region的管理者,其实现类为HRegionServer,主要作用如下:
    对于数据的操作:get,put,delete
    对于Region的操作:splitRegion、compactRegion
  2. Master
    Master是所有Region Server的管理者,其实现类为HMaster,主要作用如下:
    对于表的操作:create、delete、alter
    对于RegionServer的操作:分配regions到每个RegionServer,监控每个RegionServer的状态,负载均衡和故障转移
  3. Zookeeper
    HBase通过Zookeeper来做Master的高可用、RegionServer的监控、元数据的入口以及集群配置的维护等工作
  4. HDFS
    HDFS为HBase提供最终的底层数据存储服务,同时为HBase提供高可用的支持

二、HBase快速入门

2.1 HBase安装部署

2.1.1 Zookeeper正常部署

首先保证Zookeeper集群的正常部署,并启动之:

[ironmanjay@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start
[ironmanjay@hadoop103 zookeeper-3.4.10]$ bin/zkServer.sh start
[ironmanjay@hadoop104 zookeeper-3.4.10]$ bin/zkServer.sh start 

2.1.2 Hadoop正常部署

Hadoop集群的正常部署并启动:注意:Hadoop集群安装部署看我这篇博客

[ironmanjay@hadoop102 hadoop-2.7.2]$ sbin/start-dfs.sh
[ironmanjay@hadoop103 hadoop-2.7.2]$ sbin/start-yarn.sh

2.1.3 HBase的解压

HBase官网下载相应版本,解压HBase到指定目录(目录自己指定):

[ironmanjay@hadoop102 software]$ tar -zxvf hbase-1.3.1-bin.tar.gz -C
/opt/module 

2.1.4 HBase的配置文件

修改HBase对应的配置文件

  1. hbase-env.sh修改如下。注意:JAVA_HOME路经按照自己的来,我的注释掉怕有的读者直接复制,切记改成自己的JAVA_HOME,否则HBase安装会失败
export JAVA_HOME=#/opt/module/jdk1.6.0_144
export HBASE_MANAGES_ZK=false 
  1. hbase-site.xml修改如下
<configuration>
 	<property>
  		<name>hbase.rootdir</name>
  		<value>hdfs://你的Hadoop地址:9000/HBase</value>
	</property>
 	<property>
  		<name>hbase.cluster.distributed</name>
  		<value>true</value>
  	</property>
	<!-- 0.98 后的新变动,之前版本没有.port,默认端口为 60000 -->
	<property>
  		<name>hbase.master.port</name>
  		<value>16000</value>
	</property>
 	<property>
  		<name>hbase.zookeeper.quorum</name>
  		<value>你的Hadoop集群名称</value>
	</property>
	<property>
  		<name>hbase.zookeeper.property.dataDir</name>
  		<value>你的Zookeeper安装地址/zkData</value>
	</property>
 <configuration>
  1. regionservers。注意:这里以我的为例,填写自己的Hadoop集群名称,不要有空格等
hadoop102
hadoop103
hadoop104
  1. 软连接hadoop配置文件到HBase。注意:根据自己目录情况修改即可
[ironmanjay@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/core-site.xml /opt/module/hbase/conf/coresite.xml
[ironmanjay@hadoop102 module]$ ln -s /opt/module/hadoop-2.7.2/etc/hadoop/hdfs-site.xml /opt/module/hbase/conf/hdfssite.xml 

2.1.5 HBase远程发送到其他集群

这里用到了集群远程分发脚本,具体脚本代码看我上面Hadoop部署的博客

[ironmanjay@hadoop102 module]$ xsync hbase/ 

2.1.6 HBase服务的启动

  1. HBase服务启动
[ironmanjay@hadoop102 hbase]$ bin/start-hbase.sh 
  1. HBase服务停止
[ironmanjay@hadoop102 hbase]$ bin/stop-hbase.sh 

2.1.7 查看HBase页面

启动成功后,可以通过“host:port”的方式来访问HBase管理页面,例如:
注意:16010端口不可改变,前面的Hadoop名称根据自己的修改即可

http://hadoop102:16010

2.2 HBase Shell操作

2.2.1 基本操作

  1. 进入HBase客户端命令行
[ironmanjay@hadoop102 hbase]$ bin/hbase shell 
  1. 查看帮助命令
hbase(main):001:0> help 
  1. 查看当前数据库中有哪些表
hbase(main):002:0> list 

2.2.2 表的操作

  1. 创建表
hbase(main):002:0> create 'student','info' 
  1. 插入数据到表
hbase(main):003:0> put 'student','1001','info:sex','male'
hbase(main):004:0> put 'student','1001','info:age','18'
hbase(main):005:0> put 'student','1002','info:name','Janna'
hbase(main):006:0> put 'student','1002','info:sex','female'
hbase(main):007:0> put 'student','1002','info:age','20' 
  1. 扫描查看表数据
hbase(main):008:0> scan 'student'
hbase(main):009:0> scan 'student',{STARTROW => '1001', STOPROW =>'1001'}
hbase(main):010:0> scan 'student',{STARTROW => '1001'} 
  1. 查看表结构
hbase(main):011:0> describe 'student'
  1. 更新指定字段的数据
hbase(main):012:0> put 'student','1001','info:name','Nick'
hbase(main):013:0> put 'student','1001','info:age','100' 
  1. 查看“指定行“或”指定列族:列“的数据
hbase(main):014:0> get 'student','1001'
hbase(main):015:0> get 'student','1001','info:name' 
  1. 统计表数据行数
hbase(main):021:0> count 'student' 
  1. 删除数据
    删除某rowkey的全部数据:
hbase(main):016:0> deleteall 'student','1001' 

         删除某rowkey的某一列数据:

hbase(main):017:0> delete 'student','1002','info:sex' 
  1. 清空表数据
    注意:清空表的操作顺序为先disable,然后再truncate:
hbase(main):018:0> truncate 'student' 
  1. 删除表
    首先需要先让该表为disable状态:
hbase(main):019:0> disable 'student' 

         然后才能drop这个表,如果直接drop表,会报错:ERROR: Table student is enabled. Disable it first

hbase(main):020:0> drop 'student' 
  1. 变更表信息
    将info列族中的数据存放3个版本
hbase(main):022:0> alter 'student',{NAME=>'info',VERSIONS=>3}
hbase(main):022:0> get 'student','1001',{COLUMN=>'info:name',VERSIONS=>3} 

三、HBase进阶

3.1 架构原理

在这里插入图片描述

  1. StoreFile
      保存实际数据的物理文件,StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile(HFile),数据在每个StoreFile中都是有序的
  2. MemStore
      写缓存,由于HFile中的数据要求是有序的,所以数据是先存储在MemStore中,排好序后,等到达刷写时机才会刷写到HFile,每次刷写都会形成一个新的HFile
  3. WAL
      由于数据要经MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入Memstore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建

3.2 写流程

在这里插入图片描述
写流程:

  1. Client先访问zookeeper,获取hbase:meta表位于哪个Region Server
  2. 访问对应的Region Server,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache中,方便下次访问
  3. 与目标Region Server进行通讯
  4. 将数据顺序写入(追加)到WAL
  5. 将数据写入对应的MemStore,数据会在MemStore进行排序
  6. 向客户端发送ack
  7. 等达到MemStore的刷写时机后,将数据刷写到HFile

3.3 MemStore Flush

在这里插入图片描述
MemStore刷写时机:

  1. 当某个memstore的大小达到了hbase.hregion.memstore.flush.size(默认值128M),其所在region的所有memstore都会刷写。当memstore的大小达到了hbase.hregion.memstore.flush.size(默认值128M),*hbase.hregion.memstore.block.multplier(默认值4)时,会阻止继续往该memstore写数据
  2. 当region server中memstore的总大小达到java_heapsize*hbase.regionserver.global.memstore.size(默认值0.4),*hbase.regionserver.global.memstore.size.lower.limit(默认值0.95),region会按照其所有memstore的大小顺序(由大到小)依次进行刷写。直到region server中所有memstore的总大小减小到上述值以下。当region server中memstore的总大小达到java_heapsize*hbase.regionserver.global.memstore.size(默认值0.4)时,会阻止继续往所有的memstore写数据
  3. 到达自动刷写的时间,也会触发memstore flush。自动刷新的时间间隔由该属性进行配置hbase.regionserver.optionalcacheflushinterval(默认1小时)
  4. 当WAL文件的数量超过hbase.regionserver.max.logs,region会按照时间顺序依次进行刷写,直到WAL文件数量减小到hbase.regionserver.max.log以下(该属性名已经废弃,现无需手动设置,最大值为32)

3.4 读流程

在这里插入图片描述
读流程:

  1. Client先访问zookeeper,获取hbase:meta表位于哪个Region Server
  2. 访问对应的Region Server,获取hbase:meta表,根据读请求的namespace:table/rowkey,查询出目标数据位于哪个Region Server中的哪个Region中。并将该table的region信息以及meta表的位置信息缓存在客户端的meta cache,方便下次访问
  3. 与目标Region Server进行通讯
  4. 分别在Block Cache(读缓存),MemStore和Store File(HFile)中查询目标数据,并将查到的所有数据进行合并。此外所有数据是指同一条数据的不同版本(timestamp),或者不同的类型(Put/Delete)
  5. 将从文件中查询到的数据块(Block,HFile数据存储单元,默认大小为64KB)缓存到Block Cache
  6. 将合并后的最终结果返回给客户端

3.5 StoreFile Compaction

  由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型的(Put/Delete)有可能会分布在不同的HFile中,因此查询时需要遍历所有的HFile。为了减少HFile的个数,以及清理掉过期和删除的数据,会进行StoreFile Compaction
  Compaction分为两种,分别是Minor Compaction和Major Compaction。Minor Compaction会将临近的若干较小的HFile合并成一个较大的HFile,但不会清理过期和删除的数据。Major Compaction会将一个Store下的所有HFile合并成一个大HFile,并且会清理掉过期和删除的数据
在这里插入图片描述

3.6 Region Split

  默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的Region Server,但出于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的Region Server
    Region Split时机:

  1. 当一个region中的某个Store下的所有StoreFile的总大小超过hbase.hregion.max.filesize,该Region就会拆分(0.94版本之前)
  2. 当一个region中的某个Store下所有StoreFile的总大小超过Min(R^2 * “hbase.hregion.memstore.flush.size”,“hbase.hregion.max.filesize”),该Region就会进行拆分,其中R为当前Region Server中属于该Table的个数(0.94版本之后)
    在这里插入图片描述

四、HBase API

4.1 环境准备

使用Idea新建Maven项目后在pom.xml添加依赖

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

4.2 HBase API

  1. 获取Configuration对象
public static Configuration conf;

static{	
	//使用 HBaseConfiguration 的单例方法实例化
 	conf = HBaseConfiguration.create();
 	conf.set("hbase.zookeeper.quorum", "你的集群地址");
 	conf.set("hbase.zookeeper.property.clientPort", "2181");
}
  1. 判断表是否存在
public static boolean isTableExist(String tableName) throws MasterNotRunningException,ZooKeeperConnectionException, IOException{
 	//在 HBase 中管理、访问表需要先创建 HBaseAdmin 对象
 	HBaseAdmin admin = new HBaseAdmin(conf);
 	return admin.tableExists(tableName);
}
  1. 创建表
public static void createTable(String tableName, String...columnFamily) throws MasterNotRunningException, ZooKeeperConnectionException,IOException{ HBaseAdmin admin = new HBaseAdmin(conf);
 	//判断表是否存在
 	if(isTableExist(tableName)){
  		System.out.println("表" + tableName + "已存在");
 	}else{
  		//创建表属性对象,表名需要转字节
  		HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
  		//创建多个列族
  		for(String cf : columnFamily){
   			descriptor.addFamily(new HColumnDescriptor(cf));
  	    	}
  	//根据对表的配置,创建表
  	admin.createTable(descriptor);
  	System.out.println("表" + tableName + "创建成功! ");
   }
}
  1. 删除表
public static void dropTable(String tableName) throws MasterNotRunningException,ZooKeeperConnectionException, IOException{
 	HBaseAdmin admin = new HBaseAdmin(conf);
 	if(isTableExist(tableName)){
  		admin.disableTable(tableName);
  		admin.deleteTable(tableName);
  		System.out.println("表" + tableName + "删除成功! ");
 	}else{
 		System.out.println("表" + tableName + "不存在! ");
	}
}
  1. 获取所有数据
public static void getAllRows(String tableName) throws IOException{
 	HTable hTable = new HTable(conf, tableName);
  	//得到用于扫描 region 的对象
  	Scan scan = new Scan();
  	//使用 HTable 得到 resultcanner 实现类的对象
  	ResultScanner resultScanner = hTable.getScanner(scan);
  	for(Result result : resultScanner){
   		Cell[] cells = result.rawCells();
  		for(Cell cell : cells){
   			//得到 rowkey
   			System.out.println(" 行 键 :" +
   			Bytes.toString(CellUtil.cloneRow(cell)));
   		//得到列族
   		System.out.println(" 列 族 " +
  		Bytes.toString(CellUtil.cloneFamily(cell)));
   		System.out.println(" 列 :" +
   		Bytes.toString(CellUtil.cloneQualifier(cell)));
   		System.out.println(" 值 :" +Bytes.toString(CellUtil.cloneValue(cell)));
  		}
 	}
}
  1. 获取某一行指定“列族:列“的数据
public static void getRowQualifier(String tableName, String rowKey,String family, String qualifier) throws IOException{
 	HTable table = new HTable(conf, tableName);
 	Get get = new Get(Bytes.toBytes(rowKey));
 	get.addColumn(Bytes.toBytes(family),
 	Bytes.toBytes(qualifier));
 	Result result = table.get(get);
 	for(Cell cell : result.rawCells()){
  		System.out.println(" 行 键 :" +
  		Bytes.toString(result.getRow()));
  		System.out.println(" 列 族 " +
  		Bytes.toString(CellUtil.cloneFamily(cell)));
  		System.out.println(" 列 :" +
  		Bytes.toString(CellUtil.cloneQualifier(cell)));
  		System.out.println(" 值 :" +
  		Bytes.toString(CellUtil.cloneValue(cell)));
 	}
}

4.3 MapReduce

  通过 HBase 的相关 JavaAPI,我们可以实现伴随 HBase 操作的 MapReduce 过程,比如使用
MapReduce 将数据从本地文件系统导入到 HBase 的表中,比如我们从 HBase 中读取一些原
始数据后使用 MapReduce 做数据分析

  1. 查看HBase的MapReduce任务的执行
bin/hbase mapredcp 
  1. 配置永久生效:在/etc/profile配置
export HBASE_HOME=你的HBase安装目录
export HADOOP_HOME=你的Hadoop安装目录 
  1. 在hadoop-env.sh中配置,注意:在for循环之后配
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:你的HBase安装目录/lib/* 
  1. 运行官方的MapReduce任务,统计Student表中有多少行数据
你的hadoop安装目录/bin/yarn jar lib/hbase-server-1.3.1.jar rowcounter student 

五、HBase与Hive的对比

  1. Hive
    ①:数据仓库
      Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个双射关系,以
    方便使用 HQL 去管理查询
    ②:用于数据分析、清洗
      Hive 适用于离线的数据分析和清洗,延迟较高
    ③:基于HDFS、MapReduce
      Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行
  2. HBase
    ①:数据库
      是一种面向列族存储的非关系型数据库
    ②:用于存储结构化和非结构化的数据
      适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作
    ③:基于HDFS
      数据持久化存储的体现是HFile,存放于DataNode中,被Region Server以region的形式进行管理④:延迟较低,接入在线业务使用
      面对大量的企业数据,HBase可以进行单表大量数据的存储,同时提供了高效的数据访问速度

六、HBase优化

6.1 高可用

  在 HBase 中 HMaster 负责监控 HRegionServer 的生命周期,均衡 Region Server 的负载,如果 HMaster 挂掉了,那么整个 HBase 集群将陷入不健康的状态,并且此时的工作状态并不会维持太久。所以 HBase 支持对 HMaster 的高可用配置

  1. 关闭HBase集群(如果没有开启则跳过此步)
[ironmanjay@hadoop102 hbase]$ bin/stop-hbase.sh 
  1. 在conf目录下创建backup-masters文件
[ironmanjay@hadoop102 hbase]$ touch conf/backup-masters 
  1. 在backup-masters文件中配置高可用HMaster节点
[ironmanjay@hadoop102 hbase]$ echo hadoop103 > conf/backup-masters 
  1. 将整个conf目录scp到其他机器节点
[ironmanjay@hadoop102 hbase]$ scp -r conf/hadoop103:/opt/module/hbase/
[ironmanjay@hadoop102 hbase]$ scp -r conf/hadoop104:/opt/module/hbase/ 
  1. 打开测试页面查看
http://hadoop102:16010/

6.2 预分区

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

  1. 手动设定预分区
Hbase> create 'staff1','info','partition1',SPLITS => ['1000','2000','3000','4000'] 
  1. 生成十六进制序列预分区
create 'staff2','info','partition2',{NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'} 
  1. 按照文件中设置的规则预分区
    创建splits.txt文件内容如下
aaaa
bbbb
cccc
dddd 

         然后执行

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

6.3 内存优化

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

6.4 基础优化

  1. 允许在HDFS的文件中追加内容
    hdfs-site.xml、 hbase-site.xml
属性:dfs.support.append
解释:开启 HDFS 追加同步,可以优秀的配合 HBase 的数据同步和持久化。默认值为 true 
  1. 优化 DataNode 允许的最大文件打开数
    hdfs-site.xml
属性:dfs.datanode.max.transfer.threads
解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为 4096 或者更高。默认值:4096 
  1. 优化延迟高的数据操作的等待时间
    hdfs-site.xml
属性:dfs.image.transfer.timeout
解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000 毫秒),以确保socket不会被timeout掉
  1. 设置 RPC 监听数量
    hbase-site.xml
属性:Hbase.regionserver.handler.count
解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值 
  1. 优化 HStore 文件大小
    hbase-site.xml
属性:hbase.hregion.max.filesize
解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile 
  1. 优化 HBase 客户端缓存
    hbase-site.xml
属性:hbase.client.write.buffer
解释:用于指定Hbase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的 

猜你喜欢

转载自blog.csdn.net/IronmanJay/article/details/107291472