概述
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
启动:
备用主机:hbase-daemon.sh start master
脚本访问: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应该设置多少合适?