HBase 数据库

概述

HBase概述

​ HBase是一个分布式的、面向列的开源数据库,该技术来源于Fay Chang 所撰写的Google论文《Bigtable》一个结构化数据的分布式存储系统"。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力(低延迟的数据查询能力)。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,Hbase同BigTable一样,都是NoSQL数据库,即非关系型数据库,此外,HBase和BigTable一样,是基于列的而不是基于行的模式。

​ HBase利用Hadoop HDFS作为其文件存储系统,利用Hadoop的MapReduce来处理HBase中的海量数据,利用Zookeeper作为协调工具。

关系型数据库 VS NoSql数据库

1 关系型数据库的缺陷

  • 高并发读写的瓶颈

    ​ 目前环境下,需处理高并发的读写请求,但是关系型数据库可以支持上万次的SQL查询,但I/O硬盘无法承受上万次的SQL写入请求。

  • 可拓展性的限制

    ​ 在基于Web的架构中,数据库是最难以进行横向扩展的,当应用系统的用户量和访问量与日俱增时,数据库系统却无法像Web Server和App Server那样简单地通过添加更多的硬件和服务节点来扩展性能和负载能力。

  • 事务一致性的负面影响

    ​ 在关系型数据库中,所有的规则必须应用到事务的修改上,以便维护所有数据的完整性,这随之而来的是性能的大幅度下降。很多Web系统并不需要严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求也不高。因此数据库事务管理成了高负载下的一个沉重负担。

  • 复杂SQL查询的弱化

    ​ 任何大数据量的Web系统都非常忌讳几个大表间的关联查询,以及复杂的数据分析类型的SQL查询,特别是SNS类型的网站,从需求以及产品设计角度就避免了这种情况的产生。更多的情况往往只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大地弱化了,所以这部分功能不能得到充分发挥。

2 NoSQL数据库的优势

  • 拓展性强

    ​ NoSQL去掉了关系型数据库的关系特性,数据之间是弱关系,容易拓展,而且通常使用KV字典式存储结构,水平拓展性能优越,很容易实现支撑数据从TB到PB的过渡。

  • 并发性能好

    ​ 读写性能优良

  • 数据模型灵活

    ​ 无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

HBase的逻辑结构

1 列存储 VS 行存储

列存储 行存储
代表框架 HBase MongoDB 文档型
Lexst 二进制
组织表的方式
写入方式 把一行记录拆分成单列保存,写入次数多,刺头需要移动和定位,修改数据时,行存储是在指定位置写入一次,列存储是将磁盘定位到多个列上分别写入,这个过程仍是行存储的列数倍。 一次写入
读取方式 每次读取的数据是集合的一段或者全部,不存在冗余性问题 将一行数据完全读出,如果只需要其中几列数据的情况,就会存在冗余列,出于缩短处理时间的考量,消除冗余列的过程通常是在内存中进行的。
数据类型 一列都是相同的数据类型,全集合一个类型 一行有多种数据类型,数据解析需要在多种数据类型之间频繁转换
数据压缩性能
优点 在读取过程,不会产生冗余数据 一次性完成,消耗的时间比列存储少,并且能够保证数据的完整性
缺点 写入效率、保证数据完整性上都不如行存储 数据读取过程中会产生冗余数据
适用场景 OLAP 在线联机分析处理系统
同一个数据列的数据重复度很高
每次查询涉及的数据量较小或者大部分查询都需要整行的数

2 HBase逻辑结构

  • 行键 RowKey

    ​ HBase的主键,数据都是按照行键的字典顺序排序后存储,对于HBase的数据查询,仅有三种模式:

    • 根据指定行键查询
    • 根据指定行键范围查询
    • 全表扫描查询
  • 列族 ColumnFamily

    ​ HBase表中垂直方向保存数据的结构,列族是HBase表中的元数据的一部分,需要在定义HBase表时制定好表有哪个列族,列族可以包含一个或多个列(后面可以拓展)

  • 列 Column

    ​ HBase表中列族里可以包含一个或多个列,列并不是HBase表的元数据的一部分,不需要在创建表时预先定义,而是可以在后续使用表时随时为表的列族动态的增加列。

  • 单元格和时间戳

    ​ 在HBase表中,水平方向的行和垂直方向的列交汇就得到了HBase中的一个存储单元,而在这个存储单元中,可以存储数据,并且可以保存数据的多个版本,这些个版本之间通过时间戳来进行区分。
    ​ 所以在HBase中可以通过行键列族列时间戳来确定一个最小的存储数据的单元,这个单元就称之为单元格Cell。

    ​ 单元格中的数据都以二进制形式存储,没有数据类型的区别。

HBase搭建操作

​ 前提条件,安装jdk 和 hadoop,并配置了环境变量。

hbase-env.sh配置HBase启动时需要的相关环境变量。

hbase-site.xml配置HBase基本配置信息。

​ HBASE启动时默认使用hbase-default.xml中的配置,如果需要可以修改hbase-site.xml文件,此文件中的配置将会覆盖hbase-default.xml中的配置。

​ 修改配置后要重启hbase才会起作用。

单机模式

​ HBase将会基于普通的磁盘文件来进行工作,也即不使用HDFS作为底层存储,优点是方便,缺点是底层数据不是分布式存储,性能和可靠性没有保证,主要用作开发测试,不应用在生产环境下。

修改conf/hbase-site.xml文件

<property>
        <name>hbase.rootdir</name>
        <value>file:///<path>/hbase</value> #修改为非tmp的本地路径
</property> 

伪分布式

​ HBase采用hdfs作为存储具有完整的功能,但是只有一个节点工作,没有性能的提升,可以用作开发测试,不可用作生产环境下。

  • 修改conf/hbase-env.sh 的JAVA_HOME(27行,否则不能开启hbase shell)
  • 修改hbase-site.xml
<property>
        <name>hbase.rootdir</name> #指定的底层存储位置
        <value>hdfs://hadoop00:9000/hbase</value>
</property>
<property>
        <name>dfs.replication</name>#制定底层副本的数量,与HDFS副本数匹配
        <value>1</value>
</property>

完全分布式

  • 修改conf/hbase-env.sh 的JAVA_HOME(27行,否则不能开启hbase shell)

  • 修改hbase-site.xml

    <property>
            <name>hbase.rootdir</name> #指定底层存储位置
            <value>hdfs://hadoop00:9000/hbase</value>
    </property>
    <property>
            <name>dfs.replication</name>#指定底层HDFS副本数量
            <value>1</value>
    </property>
    <property>
            <name>hbase.cluster.distributed</name>#是否开启集群模式
            <value>true</value>
    </property>
    <property>
            <name>hbase.zookeeper.quorum</name>#配置zk
            <value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
    </property>
    
  • 修改conf/hbase-env.sh

    export HBASE_MANAGES_ZK false

    这个用来确认是否交由HBase管理zk,默认true,即HBase在关闭的时候,关闭zk

  • 修改conf/regionservers文件

    配置所有hbase的主机,每个主机独占一行,hbase在启动或关闭时,会按照书序启动或关闭对应主机中的HBase进程

管理指令

启动顺序:zk->hadoop->habase

启动:

主机:start-hbase.sh

备用主机:hbase-daemon.sh start master

访问地址:http://student01:60010

脚本访问:hbase shell

HBase基础操作

shell命令操作

指令 说明 示例
create 创建表格
指定VERSIONS,配置的是当前列族在持久化到文件系统中时,要保留几个最新的版本数据,这并不影响内存中的历史数据版本
create ‘tab1’,‘cf1’,'cf2’
create 表名,列族名1,列族名2
create ‘tab1’,{NAME=>‘c1’,VERSIONS=>3}
create 表名,{NAME=>列族名,VERSION=>版本数量}
list 查看共有的表格 list
put 添加数据 put ‘tab1’,‘row-1’,‘cf1:co11’,'aaa’
put 表名,行键名,列族名:列名,要插入的值
get 根据表名和行键查询 get ‘tab1’,‘row-1’,'colfamily1:co11’
get 表名,行键名[,列族名1[:列名],列族名2[:列名]]
scan 扫描表数据 scan ‘tab1’,{COLUMNS=>[‘colfamily1’,‘colfamily2’]}
scan 表名[,{COLUMNS=>[列族名1[:列名],列族名2[:列名]]}]
scan ‘tab1’,{RAW=>true,VERSIONS=>3}
在查询条件上加上ROW=>true 来开启历史版本数据的查询
VERSION=>3 指定查询最新的几个版本的数据
deleteall 根据表名、行键删除整行数据 deleteall ‘tab1’,‘row-1’
disable 禁用表 disable ‘tab1’
drop 删除表,前提是先禁用表 drop ‘tab1’

API操作

1 表格创建 / 删除

@Test
public void testCreateTable() throws Exception{
	Configuration conf=HBaseConfiguration.create();
	conf.set("hbase.zookeeper.quorum",
		"student01:2181,student02:2181,student03:2181");
	HBaseAdmin admin = new HBaseAdmin(conf);
	//指定表名
	HTableDescriptor tab1=new HTableDescriptor(TableName.valueOf("tab1"));
	//指定列族名
	HColumnDescriptor colfam1=new HColumnDescriptor("colfam1".getBytes());
	HColumnDescriptor colfam2=new HColumnDescriptor("colfam2".getBytes());
	//指定历史版本存留上限
	colfam1.setMaxVersions(3);	
	tab1.addFamily(colfam1);
	tab1.addFamily(colfam2);
	//1.创建表
	admin.createTable(tab1);
    //2.删除表
    admin.disableTable("tab1".getBytes());
	admin.deleteTable("tab1".getBytes());
    //释放资源
	admin.close();	
}

2 数据新增 / 删除

@Test
//前提,表格已创建
	public void testInsert() throws Exception{
		Configuration conf=HBaseConfiguration.create();
		conf.set("hbase.zookeeper.quorum",
			"student01:2181,student02:2181,student03:2181");
		//尽量复用Htable对象
		HTable table=new HTable(conf,"tab1");
        //指定行键
		Put put=new Put("row-1".getBytes());
		//列族,列,值
		put.add("colfam1".getBytes(),"col1".getBytes(),"aaa".getBytes());
		put.add("colfam1".getBytes(),"col2".getBytes(),"bbb".getBytes());
		table.put(put);
        //2.删除数据
       Delete del = new Delete("row-1".getBytes());
       tab.delete(del);
		table.close();
}

3 获取数据 Get

@Test
public void testGet() throws Exception{
	Configuration conf=HBaseConfiguration.create();
	conf.set("hbase.zookeeper.quorum",
			"student01:2181,student02:2181,student03:2181");
	HTable table=new HTable(conf,"tab1");
	Get get=new Get("row1".getBytes());
	Result result=table.get(get);
	byte[] col1_result=result.getValue("colfam1".getBytes(),"col".getBytes());
	System.out.println(new String(col1_result));
	table.close();
}

4 获取数据集 Scan

//获取row100及以后的行键的值,new Scan(开始行键,结束行键)
Scan scan = new Scan("row100".getBytes());
ResultScanner scanner = table.getScanner(scan);
Iterator it = scanner.iterator();
while(it.hasNext()){
	Result result = (Result) it.next();
    //Byte.toBytes等同于getBytes()
	byte [] bs = result.getValue(Bytes.toBytes("colfam1"),Bytes.toBytes("col"));
	String str = Bytes.toString(bs);
	System.out.println(str);
}

过滤器操作

​ 表的查询分为三种:

  • 根据指定行键查询
  • 根据指定行键范围查询
  • 全表扫描查询

1 根据行键范围查询

HTable table = new HTable(conf,"tab1".getBytes());
//获取指定行键范围的scan
Scan scan=new Scan();
scan.setStartRow("row1".getBytes());//指定开始行键
scan.setStopRow("row50".getBytes());//指定结束行键
//获取结果集
ResultScanner rs=table.getScanner(scan);
Result r = null;
while((r = rs.next())!=null){
	String rowKey=new String(r.getRow());
    //指定列族和列获取值
	String col1Value=new String(
       r.getValue("colfam1".getBytes(), "col".getBytes()));
	System.out.println(rowKey+":"+col1Value);
}

2 正则过滤器 RegexStringComparator

Scan scan=new Scan();
//--指定行键:RowFilter【正则过滤器】
//
Filter filter=new RowFilter(
    //比较条件,过滤器设置
    CompareOp.EQUAL,new RegexStringComparator("^.*3.*$"));
//--加入过滤器
scan.setFilter(filter);

3 行键比较过滤器 BinaryComparator

Scan scan=new Scan();		
//--指定行键:RowFilter行键【比较过滤器】
Filter filter=new RowFilter(
    //比较条件,过滤器设置
    CompareOp.LESS_OR_EQUAL,new BinaryComparator("row90".getBytes()));
scan.setFilter(filter);

4 行键前缀过滤器 PrefixFilter

Scan scan=new Scan();
//--行键前缀过滤器
Filter filter=new PrefixFilter("row3".getBytes());
scan.setFilter(filter);	

5 列值过滤器 SingleColumnValueFilter

Scan scan=new Scan();
//--列值过滤器
Filter filter = new SingleColumnValueFilter(
    //指定列族名,指定列名,比较条件,指定列值
    "cf1".getBytes(),"name".getBytes(), 
    CompareOp.EQUAL, "rose".getBytes());
scan.setFilter(filter);

HBase架构

架构组成

1.HMaster节点

2.HRegionServer节点

3.ZooKeeper集群

​ Hbase的数据存储于HDFS中,因而涉及到HDFS的NameNode、DataNode等。RegionServer和DataNode一般会放在相同的Server上实现数据的本地化(避免或减少数据在网络中的传输,节省带宽)。

HMaster

作用:

  • 管理HRegionServer,实现其负载均衡。

  • 管理和分配HRegion

    1 分配新HRegion:在HRegion split时分配新的HRegion

    2 故障迁移:在HRegionServer退出时迁移其内的HRegion到其他HRegionServer上

  • 实现DDL操作(Data Definition Language)

    namespace和table的增删改,column familiy的增删改等)。

  • 管理namespace和table的元数据

    实际存储在HDFS上,hbase目录下

  • 权限控制(ACL)

HRegionServer

作用:

  • 存放和管理本地HRegion。

  • 读写HDFS,管理Table中的数据。

  • Client直接通过HRegionServer读写数据

    从HMaster中获取元数据,找到RowKey所在的HRegion/HRegionServer后进行操作。

ZooKeeper

作用:

  • 存放整个 HBase集群的元数据以及集群的状态信息,以及RS服务器的运行状态
  • 实现HMaster主备节点的failover。

注意:

​ HBase Client通过RPC方式HMaster、HRegionServer通信

​ 一个HRegionServer可以存放1000个HRegion(来自于Google的Bigtable论文)

​ 底层Table数据存储于HDFS中

​ HRegion所处理的数据尽量和数据所在的DataNode在一起,实现数据的本地化

​ 但数据本地化并不是总能实现,比如在HRegion移动(如因Split)时,需要等下一次Compact才能继续回到本地化。

物理存储结构

Hbase里的一个Table 在行的方向上分割为多个Hregion。

即HBase中一个表的数据会被划分成很多的HRegion,HRegion可以动态扩展并且HBase保证HRegion的负载均衡。HRegion实际上是行键排序后的按规则分割的连续的存储空间。

一张Hbase表,可能有多个HRegion,每个HRegion达到一定大小(默认是10GB)时,进行分裂。

在这里插入图片描述

HBase原理说明

数据写入

在这里插入图片描述

客户端:

**1 寻址定位:**向HMaster索取HRegionServer位置

**2 发送请求:**向HRegionServer发送Put请求

HRegionServer

1 持久化日志

​ 将WAL日志写入HLog,HLog实际位于HDFS中

2 写入MemStore

​ 根据表名和行键找到对应的HRegion

​ 根据列族找到对应的Store,将数据写入对应的memStore

​ MemStore内部对数据进行行键排序,使用LSM-TREE进行数据合并

​ LSM树(Log-Structured Merge Tree)存储引擎和B树存储引擎一样,同样支持增、删、读、改、顺序扫描操作。而且通过批量存储技术规避磁盘随机写入问题。但对比B+树,LSM树牺牲了部分读性能,用来大幅提高写性能。

​ LSM树的设计思想:将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操作批量写入磁盘(溢写过程),不过读取的时候稍微麻烦,需要合并磁盘中历史数据和内存中最近修改操作,所以写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。极端的说,基于LSM树实现的HBase的写性能比Mysql高了一个数量级,读性能低了一个数量级

3 MemStore溢写

​ MemStore达到一定条件时,会溢写出一个storeFile,并同步向HDFS溢写一个HFile进行持久化

​ 溢写完成时,HBase会将最后一条持久化到HFile的日志编号记录到ZK的redo point中

溢写条件

  • 单个MemStore大小超容

    hbase.hregion.memstore.flush.size的大小,默认128MB

  • RS服务器上所有MemStore大小超容

    hbase.regionserver.global.memstore.upperLimit的大小,默认35%的内存使用量。

    从最大的Memstore开始flush,每个都可能被flush

  • RS服务器上WAL(Hlog)超过了1GB

    hbase.regionserver.hlog.blocksize(32MB) * hbase.regionserver.max.logs(32)

    前HRegionServer中所有HRegion中的MemStore都会Flush

​ MemStore还会在StoreFile尾部追加一些meta数据,其中就包括Flush时最大的WAL sequence值,以告诉HBase这个StoreFile写入的最新数据的序列,那么在Recover时就直到从哪里开始。在HRegion启动时,这个sequence会被读取,并取最大的作为下一次更新时的起始sequence。


补充:StoreFile(Hlog)结构

​ 一个StoreFile分为DataBlock、MetaBlock、 FileInfo、 DataIndex、 MetaIndex、 Trailer

  • Data Blocks

    ​ 保存表中的数据,这部分可以被压缩

    ​ DataBlocks中存放了大量的DataBlock,其中以键值对的形式保存着表中的数据,其中 键是行键,值是该行的某一个列的值,所以一个HBase表中的一个行可能在底层存在多键值对保存

  • Meta Blocks (可选的) :保存用户自定义的kv对,可以被压缩。

  • File Info:Hfile的元信息,不被压缩,用户也可以在这一部分添加自己的元信息。

  • Data Block Index:Data Block的索引

  • Meta Block Index (可选的):Meta Block的索引。

  • Trailer

    ​ 这一段是定长的。保存了每一段的偏移量,读取一个HFile时,会首先 读取Trailer,Trailer保存了每个段的起始位置


数据读取

Where is the Cell?

新写入的Cell,存在于MemStore中;

之前已经Flush到HFile中的Cell,存在于某个或某些StoreFile(HFile)中

刚读取过的Cell,可能存在于BlockCache中

客户端

向HBase发送读取表格的请求

HMaster

根据表和行键确定HRegion,找到对应的HRegionServer

HRegionServer

1 内存返回:查询MemStore,寻找数据,查到,返回

2 硬盘返回:查询Store对应的所有storeFile(并行),解析storeFile

​ 读取Trailer模块,找到DataBlockIndex,根据索引判断查找的数据在当前storeFile中是否存在。

​ 存在即找到对应DataBlocks中的DataBlock返回,不存在直接返回空。

​ 如果查询了多个DataBlocks 返回了多个DataBlock,先在内存中合并再返回查询结果

HBase中扫瞄的顺序依次是:BlockCache、MemStore、StoreFile(HFile)(为了减少磁盘的I/O次数)

其中StoreFile的扫瞄先会使用**Bloom Filter(布隆过滤算法)**过滤那些不可能符合条件的HFile,然后使用Block Index快速定位Cell,并将其加载到BlockCache中,然后从BlockCache中读取。

我们知道一个HStore可能存在多个StoreFile(HFile),此时需要扫瞄多个HFile,如果HFile过多又是会引起性能问题。

Bloom Filter 通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。此外,引入布隆过滤器会带来一定的内存消耗。


合并机制 Compaction

Minor Compaction

​ 默认,选取一些小的、相邻的StoreFile将他们合并成一个更大的StoreFile(结果是多个),不处理Deleted\Expired的Cell

Major Compaction

​ 将所有的StoreFile合并成一个StoreFile(结果是一个),在这个过程中,标记为Deleted的Cell会被删除,而那些已经Expired的Cell会被丢弃,那些已经超过最多版本数的Cell会被丢弃。Major Compaction可能会代理大量的磁盘I/O,从而阻塞Hbase其他的读写操作。所以对于Major Compactoin,一般选择在业务峰值低的时候执行。

Compaction的实现

  • API

    admin.compact(“tab2”.getBytes()); //minor

    admin.majorCompact(“tab2”.getBytes()); //major

  • 指令

    compact(‘tab2’)

    major_compact(‘tab2’)

HBase表设计

列族设计

  • 列族越少越好,官推不超过3个

  • 经常一起查询的数据放在一个列族,减少跨列数据访问

    同一个行键范围的数据会存储在同一个store

  • 多列族设计需要考虑数据倾斜问题

    防止由于列族之间的数据量不均匀,造成在region分裂的过程中,某些region越切越小,影响后续查询效率

行键设计

设计原则

  • 行健必须唯一
  • 行健必须有意义
  • 行键最好是字符串:数值类型在不同系统中处理方式可能不同,例如js中1的实际值为1.0
  • 行键最好有固定长度:不同长度会导致排序结果与预期相悖
  • 行键不宜过长:最多可达64kb,最好在10-100以内,最好不超过16字节,最好是8字节的倍数,方便底层存储形成一个单元。

最佳实践

  • 散列原则

    ​ 行键的设计将会影响数据在hbase表中的排序方式,这会影响region切分后的结果,要注意,在设计行键时应该让经常被查询的热点数据分散在不同的region中,防止某一个或某几个regionserver成为热点。

  • 有序原则

    ​ 行键的设计将会影响数据在hbase表中的排序方式,所以一种策略是通过设计行键将将经常连续查询的数据排列在一起,这样一来可以方便批量查询

HBase的优化

硬件和操作系统调优

配置内存

​ HBase对于内存的消耗是非常大的,主要是其LSM树状结构、缓存机制和日志记录机制决定的,所以物理内存当然是越大越好。如果资源很紧张,推荐内存最小在32GB,如果再小会严重影响HBase集群性能。

配置CPU

​ HBase在某些应用上对CPU的消耗非常大,例如频繁使用过滤器,因为在过滤器中包含很多匹配、搜索和过滤的操作;多条件组合扫描的场景也是CPU密集型的;压缩操作很频繁等。如果服务器CPU不够强悍,会导致整个集群的负载非常高,很多线程都在阻塞状态(非网络阻塞和死锁的情况)。

垃圾回收机制的选择

​ 对于运行HBase相关进程JVM的垃圾回收器,不仅仅关注吞吐量,还关注停顿时间,而且两者之间停顿时间更为重要,因为HBase设计的初衷就是解决大规模数据集下实时访问的问题。那么按照首位是停顿时间短,从这个方面CMS和G1有着非常大的优势。

​ 而CMS作为JDK1.5已经出现的垃圾收集器,已经成熟应用在互联网等各个行业。所以,选用CMS作为老年代的垃圾回收器。与CMS搭配的新生代收集器有Serial和ParNew,而对比这两个收集器,明显ParNew具有更好的性能,所以新生代选用ParNew作为垃圾收集器。那么,最终选用的垃圾收集器搭配组合是CMS+ParNew。而且很多成熟应用已经验证了这种组合搭配的优势。

配置方式:需要添加到hbase-env.sh文件中

export HBASE_OPTS="-XX:+UseConcMarkSweepGC" -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSCompactAtFullCollection

JVM堆大小设置

​ 堆内存大小参数hbase-env.sh文件中设置,设置的代码如下:

export HBASE_HEAPSIZE=16384

​ 在上面代码中指定堆内存大小是16284,单位是MB,即16GB。当然,这个值需要根据节点实际的物理内存来决定。一般不超过实际物理内存的1/2。

​ 服务器内存的分配,比如服务器内存64GB,为操作系统预留出8G16GB。此外给Yarn留出8G16GB,如果没有其他框架,把剩余的留给HBase。

HBase调优

1 调节数据块大小

  • ​ 55

  • 提升随机查找性能-> 调小

    ​ 数据块大小的设置影响数据块索引的大小。数据块越小,索引越大,从而占用更大内存空间。同时加载进内存的数据块越小,随机查找性能更好。

  • 提升序列扫描性能-> 调大

    ​ 如果需要更好的序列扫描性能,那么一次能够加载更多HFile数据进入内存更为合理,这意味着应该将数据块设置为更大的值。相应地,索引变小,将在随机读性能上付出更多的代价。

2 适当时机关闭数据块缓存

​ 块缓存默认是打开的。

原因:

​ 如果一个表或表的列族只被顺序化扫描访问或很少被访问,则Get或Scan操作花费时间长一点是可以接受的。在这种情况下,可以选择关闭列族的缓存。

​ 如果只是执行很多顺序化扫描,会多次使用缓存,并且可能会滥用缓存,从而把应该放进缓存获得性能提升的数据给排挤出去。

可以在新建表或更改表时关闭数据块缓存属性:

hbase(main):002:0> create ‘mytable’, {NAME => ‘colfam1’, BLOCKCACHE => ‘false’}

3 开启布隆过滤器

​ 布隆过滤器(Bloom Filter)允许对存储在每个数据块的数据做一个反向测验。当查询某行时,先检查布隆过滤器,看看该行是否不在这个数据块。布隆过滤器要么确定回答该行不在,要么回答不知道。因此称之为反向测验。布隆过滤器也可以应用到行内的单元格上,当访问某列标识符时先使用同样的反向测验。

​ 使用布隆过滤器也不是没有代价,相反,存储这个额外的索引层次占用额外的空间。布隆过滤器的占用空间大小随着它们的索引对象数据增长而增长,所以行级布隆过滤器比列标识符级布隆过滤器占用空间要少。当空间不是问题时,它们可以压榨整个系统的性能潜力。

​ 可以在列族上打开布隆过滤器,代码如下:

​ hbase(main):007:0> create ‘mytable’, {NAME => ‘colfam1’, BLOOMFILTER => ‘ROWCOL’}

​ 布隆过滤器参数的默认值是NONE。另外,还有两个值:ROW表示行级布隆过滤器;ROWCOL表示列标识符级布隆过滤器。

​ 行级布隆过滤器在数据块中检查特定行键是否不存在,列标识符级布隆过滤器检查行和列标识符联合体是否不存在。ROWCOL布隆过滤器的空间开销高于ROW布隆过滤器

4 开启数据压缩

​ HFile可以被压缩并存放在HDFS上,这有助于节省硬盘I/O,但是读写数据时压缩和解压缩会抬高CPU利用率。压缩是表定义的一部分,可以在建表或模式改变时设定。除非确定压缩不会提升系统的性能,否则推荐打开表的压缩。只有在数据不能被压缩,或者因为某些原因服务器的CPU利用率有限制要求的情况下,有可能需要关闭压缩特性。

​ HBase可以使用多种压缩编码,包括LZO、SNAPPY和GZIP,LZO和SNAPPY是其中最流行的两种。

​ 当建表时可以在列族上打开压缩,代码如下:

create ‘mytable’, {NAME => ‘colfam1’, COMPRESSION => ‘SNAPPY’}

​ 注意,数据只在硬盘上是压缩的,在内存中(MemStore或BlockCache)或在网络传输时是没有压缩的。

5 设置Scan缓存

​ HBase的Scan查询中可以设置缓存,定义一次交互从服务器端传输到客户端的行数,设置方法是使用Scan类中setCaching()方法,这样能有效地减少服务器端和客户端的交互,更好地提升扫描查询的性能。

6 指定列操作

​ 如果在查询中指定某列或者某几列,能够有效地减少网络传输量,在一定程度上提升查询性能。



面试题

hbase udf继承哪个类?

说一下Hbase 中Hlog作用

Hbase的二级索引

hbase缺点

hive如何从hbase中读取数据?

hive和hbase比较一下,各自优势,应用场景

hbase的region

hbase如何导入超大文件

hbase行键建立时需要注意哪些?

hbase内部原理

介绍下hbase写入数据流程

Hbase 在进行模型设计时重点在什么地方?一张表中定义多少个column Family最合适?为什么?

如何提高Hbase客户端读写性能?请举例说明。

Hbase如何存储数据?

设计一个Hbase表rowkey带有时间字段,方便做Scan时按时间进行索引,又能方便做随机读写,并保持各regionserver数据
请求比较均衡

Hbase内部机制是什么?

描述Hbase scan和get有何异同?

Hbase和Hive有什么区别?

简单描述Hbase的rowkey的设计原理?

请描述Hbase中scan和get的功能以及实现的异同

请描述Hbase中scan对象的setCache和setBatch方法的使用

请详细描述Hbase中一个Cell的结构

请描述如何处理Hbase中region太多和region太大带来的冲突

HDFS和Hbase各自使用场景

Hbase的rowkey设计,影响Hbase的性能有哪些?

Hbase行键设计规范

hbase中compact的用途,什么时候触发,分哪两种,有什么区别,有哪些配置参数?

hbase中如何防止数据倾斜?

hbase单服务器节点下最大管理空间能到多少TB,最大管理空间受哪些因素影响?

Hbase的rowkey设计,影响Hbase的性能有哪些?

Hbase,Hregion,max,filesize应该设置多少合适?

猜你喜欢

转载自blog.csdn.net/weixin_42712876/article/details/84639674