第1节HBase简介
1.1 HBase是什么
HBase基于Google的BigTable论文而来。是一个分布式海量列式非关系型分布式数据库系统。可以提供超大规模数据集的实时随机读写.
列存储的优点:
1)减少存储空间占用。
2)支持好多列
1.2 HBase的特点
●海量存储:底层基于HDFS存储海量数据
●列式存储: HBase表的数据是基于列族进行存储的,一个列族包含若干列
●极易扩展:底层依赖HDFS,当磁盘空间不足的时候。只需要动态增加DataNode服务节点就可以
●高并发:支持高并发的读写请求
●稀疏:稀疏主要是针对HBase列的灵活性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占用存储空间的。
●数据的多版本: HBase表中的数据可以有多个版本值,默认情况下是根据版本号去区分,版本号就是插入数据的时间戰
●数据类型单一:所有的数据在HBase中是以字节数组进行存储
1.3 HBase的应用
●交通方面:船舶GPS信息,每天有上干万左右的数据存储。
●金融方面:消费信息、贷款信息、信用卡还款信息等
●电商方面:电商网站的交易信息、物流信息、游览信息等
●电信方面:通话信息
总结: HBase适合海量明细数据的存储,并且后期需要有很好的查询性能(单表超干万、上亿。且并发要求高)
概念 | 描述 |
命名空间 | 类似于关系型数据库的database概念,每个命名空间下有多个表。HBase两个自带的命名空间,分别是hbase和default, hbase中存放的是HBase内置的表,default表 是用户默认使用的命名空间。一个表可以自由选择是否有命名空间,如果创建表的时候加上了命名空间后,这个表名字以<Namespace>;<Tab7e>作为区分! |
Table | 类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,数据属性,比如超时时间(TTL),压缩算法(COMPRESION) 等,都在列族的定义中定义,不需要声明具体的列。 |
Row (一行逻辑数据) | HBase表中的每行数据都由一个RowKey和多个Column (列)组成。-个行包含了多个列,这些列通过列族来分类行中的数据所属列族只能从该表所定,义的列族中选取,不能定义这个表中不存在的列族,否则报错NoSuchColumnFamilyException. |
RowKey (每行数据主键) | Rowkey由用户指定的-串不重复的字符串定义,是一行的唯一标识!数据是按照RowKey的字典顺序存储的,井且查询数据时只能根据RowKey进行检索,所以RowKey的设计十分重要。如果使用了之前已经定义的RowKey,那么会将之前的数据更新掉! |
Column Family | 列族是多个列的集合。一个列族可以动态地灵活定义多个列。表的相关属性大部分都定义在列族上,同一个表里的不同列族可以有完全不同的属性配置,但是同一个列族内的所有列都会有相同的属性。列族存在的意义是HBase会把相同列族的列尽量放在同一台机器上,所以说,如果想让某几个列被放到一起,你就给他们定义相同的列族。 |
Column Qualifier | Hbase中的列是可以随意定义的,一个行中的列不限名字、不限数量,只限定列族。因此列必须依赖于列族存在! 列的名称前必须带着其所属的列族!例如info: name, info: age |
TimeStamp | 用于标识数据的不同版本(version) 。时间戳默认由系统指定,也可以由用户显式指定。在读取单元格的数据时,版本号可以省略,如果不指定,Hbase默认会获取最后一个版本的数据返回! |
Cell | 一个列中可以存储多个版本的数据。而每个版本就称为一个单元格(Cell) 。 |
Region | Region由一个表的若干行组成!在Region中行的排序按照行键(rowkey) 字典排序。Region不能跨RegionSever,且当数据量大的时候,HBase会拆分Region. |
Zookeeper
●实现了HMaster的高可用
。保存了HBase的元数据信息,是所有HBase表的寻址入口
●对HMaster和HRegionServer实现了监控
HMaster (Master)
●为HRegionServer分配Region
。维护整个集群的负载均衡
●维护集群的元数据信息
●发现失效的Region, 并将失效的Region分配到正常的HRegionServer上
HRegionServer (RegionServer)
●负责管理Region
●接受客户端的读写数据请求
●切分在运行过程中变大的Region
Region
●每个HRegion由多个Store构成,
●每个Store保存一个列族(Columns Famil),表有几个列族,则有几个Store,
●每个Store由一个MemStore和多个StoreFile组成, MemStore是Store在内存中的内容, 写到文件后就是StoreFile. StoreFile底层是以HFile的格式保存。
hbase高可用的配置:
在hbase的conf目录下创建文件backup-masters(standby-master):
echo “slave2” > /usr/local/hbase/conf/backup-master
修改hbase-site.xml配置文件:
<property>
<name>hbase.rootdir</name>
<value>hdfs://mycluster/hbase</value>
<description>数据写入目录为hdfs中的hbase目录,使用master的9000端口。不配置该选项默认为/tmp/hbasse/${user.name}的,也就是说,重启会丢失数据(重启时操作系统会清理/tmp目录)</description>
</property>
hbase基本操作:
建表:表名是lagou,列簇两个base_info、external_info
hbase:001:0> create ‘lagou’,‘base_info’,‘external_info’
或者 【指定版本为3,NAME和VERSIONS都是大写,特定的词,不可用使用小写】
hbase:015:0> create ‘lagou1’,{NAME => ‘base_info’,VERSIONS => ‘3’},{NAME => ‘external_info’,VERSIONS => ‘3’}
查询表:
hbase:016:0> list
添加数据:
向lagou表中插入数据:
hbase:017:0> put ‘lagou’,‘rk1’,‘base_info:name’,‘chen’ ##【row key为rk1,列簇base_info下有name列,值为chen】
hbase:018:0> put ‘lagou’,‘rk1’,‘base_info:age’,‘28’ ##【在列簇base_info下新增列age,值为28】
hbase:024:0> put ‘lagou’,‘rk1’,‘external_info:address’,‘beijing’ ##【在lagou表中,列簇external_info下添加列address,值为beijing】
查询数据:
1,通过row key查询:
1.1获取row key为rk1的所有信息:
hbase:026:0> get ‘lagou’,‘rk1’
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
base_info:name timestamp=2021-06-12T13:57:06.461, value=chen
external_info:address timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 1.2093 seconds
1.2查看row key下面某个列簇的信息:
获取lagou表中row key为rk1的base_info列簇信息:
hbase:027:0> get ‘lagou’,‘rk1’,‘base_info’
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
base_info:name timestamp=2021-06-12T13:57:06.461, value=chen
1 row(s)
Took 0.0609 seconds
1.3查看rowkey的指定列簇,指定字段(列)的值:
获取lagou表中row key为rk1的base_info列簇下的age的信息:
hbase:031:0> get ‘lagou’,‘rk1’,‘base_info:age’
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
1 row(s)
Took 0.0373 seconds
2,查看指定的多个列簇的信息
hbase:032:0> get ‘lagou’,‘rk1’,‘base_info’,‘external_info’
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
base_info:name timestamp=2021-06-12T13:57:06.461, value=chen
external_info:address timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 0.0106 seconds
3,指定rowkey与列值查询
获取lagou表中row key为rk,cell的值为chen的信息:
hbase:038:0> get ‘lagou’,‘rk1’,{FILTER => “ValueFilter(=,‘binary:chen’)”} ##指定过滤器:FILTER。过滤器为ValueFilter过滤器(列值过滤器),binary(二进制)值为chen的信息
COLUMN CELL
base_info:name timestamp=2021-06-12T13:57:06.461, value=chen
1 row(s)
Took 0.8322 seconds
hbase:039:0> get 'lagou','rk1',{FILTER => "ValueFilter(=,'binary:28')"} ##指定过滤器:FILTER。过滤器为ValueFilter过滤器(列值过滤器),binary(二进制)值为28的信息
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
1 row(s)
Took 0.0436 seconds
4,指定rowkey与列值模糊查询:
获取lagou表中row key为rk1,列标示符中含有‘a’的信息:
hbase:048:0> get 'lagou','rk1',{FILTER => "(QualifierFilter(=,'substring:a'))"}
COLUMN CELL
base_info:age timestamp=2021-06-12T13:58:49.052, value=28
base_info:name timestamp=2021-06-12T13:57:06.461, value=chen
external_info:address timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 0.2023 seconds
5,查询所有的数据【全表扫描,不建议使用】
hbase:049:0> scan 'lagou'
ROW COLUMN+CELL
rk1 column=base_info:age, timestamp=2021-06-12T13:58:49.052, value=28
rk1 column=base_info:name, timestamp=2021-06-12T13:57:06.461, value=chen
rk1 column=external_info:address, timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 0.2290 seconds
6,列簇查询
查询表中列簇为base_info的信息
hbase:054:0> scan 'lagou',{COLUMNS => 'base_info'}
ROW COLUMN+CELL
rk1 column=base_info:age, timestamp=2021-06-12T13:58:49.052, value=28
rk1 column=base_info:name, timestamp=2021-06-12T13:57:06.461, value=chen
1 row(s)
Took 0.0830 seconds
或者
##Scan时可以设置是否开启Raw模式,开启Raw模式会返四包括已添加删除标记但是未实际删除的数据
##VERSIONS指定查询的最大版本数
hbase:061:0> scan 'lagou',{COLUMNS => 'base_info',RAW => true,VERSIONS => 3}
ROW COLUMN+CELL
rk1 column=base_info:age, timestamp=2021-06-12T13:58:49.052, value=28
rk1 column=base_info:name, timestamp=2021-06-12T13:57:06.461, value=chen
1 row(s)
Took 0.0191 seconds
7,指定多个列簇和按照数据值模糊查询
查询lagou表中列簇为base_info、external_info且列标示符(列名)中含有d字符的信息
hbase:079:0> scan 'lagou',{COLUMNS => ['base_info','external_info'],FILTER => "(QualifierFilter(=,'substring:d'))"}
ROW COLUMN+CELL
rk1 column=external_info:address, timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 0.0046 seconds
8,根据rowkey范围查询(很重要且常用)【rowkey底层存储是字典排序】
查询lagou表中列簇为base_info,rk范围是[rk1,rk3)的数据【注意,该范围为左闭右开】
按rowkey的顺序存储
hbase:085:0> scan 'lagou',{COLUMNS => 'base_info',STARTROW=>'rk1',ENDROW=>'rk3'}
ROW COLUMN+CELL
rk1 column=base_info:age, timestamp=2021-06-12T13:58:49.052, value=28
rk1 column=base_info:name, timestamp=2021-06-12T13:57:06.461, value=chen
1 row(s)
Took 0.5130 seconds
9,指定rowkey模糊查询
查询lagou表中rowkey以rk开头的
hbase:088:0> scan 'lagou',{FILTER=>"PrefixFilter('rk')"}
ROW COLUMN+CELL
rk1 column=base_info:age, timestamp=2021-06-12T13:58:49.052, value=28
rk1 column=base_info:name, timestamp=2021-06-12T13:57:06.461, value=chen
rk1 column=external_info:address, timestamp=2021-06-12T14:01:08.402, value=beijing
1 row(s)
Took 0.1708 seconds
10,更新数据
更新同插入操作一样,只不过有数据就更新,没数据就插入
hbase:089:0> put 'lagou','rk1','base_info:name','tian'
Took 0.0571 seconds
hbase:090:0> put 'lagou','rk2','base_info:age','25'
Took 0.0204 seconds
11,删除数据和表
删除lagou表rowkey为rk1,列标示符为habse_info的数据:
hbase:007:0> delete 'lagou','rk1','base_info:age'
Took 0.7793 seconds
12,删除列簇
hbase:011:0> alter 'lagou','delete'=>'base_info'
Updating all regions with the new schema...
1/1 regions updated.
Done.
Took 3.0403 seconds
13,清空表
hbase:013:0> truncate 'lagou'
Truncating 'lagou' table (it may take a while):
Disabling table...
Truncating table...
Took 3.1438 seconds
14,删除表【删除以前先禁用,否则会出错】
hbase:014:0> disable 'lagou'
Took 0.3417 seconds
hbase:015:0> drop 'lagou'
Took 0.3837 seconds
hbase读数据流程:
●HBase读操作
1)首先从zk找到meta表的region位置,然后读取meta表中的数据,meta表中存储了用户表的region信息
2)根据要查询的namespace. 名和rowkey信息。找到写入数据对应的region信息
3)找到这个region对应的regionServer,然后发送请求
4)查找对应的region
5)先从memstore查找数据,如果没有,再从BlockCache. 上读取HBase上Regionserver的内存分为两个部分
。一部分作为Memstore,主要用来写;
。另外一部分作为BlockCache, 主要用于读数据;
6)如果BlockCache中也没有找到,再到StoreFile 上进行读取
从storeFile中读取到数据之后,不是直接把结果数据返回给客户端,
而是把数据先写入到BlockCache中,目的是为了加快后续的查询;然后在返回结果给客户端。
●HBase写操作
1)首先从zk找到meta表的region位置,然后读取meta表中的数据,meta表中存储了用户表的region信息
2)根据namespace.表名和rowkey信息找到写入数据对应的region信息
3)找到这个region对应的regionServer, 然后发送请求
4)把数据分别写到HLog (write ahead log)和memstore各一份
5) memstore达到阈值后把数据刷到磁盘,生成storeFile文件
6)删除HLog中的历史数据
hbase的flush(刷写磁盘)及compact(合并)机制
flush机制:
1)当memstore的大小超过这个值的时候,会flush到磁盘,默认为128M
hbase.hregion.memstore.flush.size
134217728
2)当memstore中数据时间超过1小时,会flush到磁盘
hbase.regionserver.optionalcacheflushinterval
3600000
3)HRegionServer的全局memstore的大小,超过该大小会触发flush到磁盘的操作,默认是堆大小的40%
hbase.regionserver.global.memstore.size
0.4
4)手动fulsh
flush tableaName
阻塞机制:
以上介绍的是Store中memstore数据刷写磁盘的标准,但是Hbase中是周期性的检查是否满足以上标准满足则进行刷写,但是如果在下次
检查到来之前,数据疯狂写入Memstore中,会出现什么问题呢?
会触发阻塞机制,此时无法写入数据到Memstore,数据无法写入Hbase集群。
●memstore中数据达到512MB
计算公式: hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block.multiplier
hbase.hregion.memstore.flush.size刷写的阀值,默认是134217728,即128MB.
hbase.hregion.memstore.block.multiplier是一个倍数,默认是4.
●RegionServer全部memstore达到规定值
hbase.regionserver.global.memstore.size.lower.limit是0.95,
hbase.regionserver.global.memstore.size是0.4
堆内存总共是16G,
触发刷写的阈值是: 6.08GB
触发阻塞的阈值是: 6.4GB
注意:缓解阻塞的一种方法就是增大内存。
Compact合井机制:
●在hbase中主要存在两种类型的compac合并
(1)minor compact小合并
1)在将Store中多个Hfile(StoreFile)合并为一个HFile
这个过程中,刚除和更新的数据仅仅只是做了标记,并没有物理移除,这种合并的能发领率很高,
2)minor compact文件选择标准由以下几个参数共同决定:
<!--待合并文件数据必须大于等于下面这个值-->
<property>
<name>hbase.hstore.compaction.min</name>
<va1ue>3</va lue>
</property>
<!--待合并文件数据必须小于等于下面这个值-->
<property>
<name>hbase.hstore.compaction.max</name>
<value>10</value>
</property>
<!--默认值为128m,表示文件大小小于该值的store file一定会加入到minor compaction的store file中-->
<property>
<name>hbase.hstore.compaction.min.size</name>
<value>134217728</value>
</property>
<!--默认值为128m,表示文件大小小于该值的store file 一定会加入到minor compaction的store file中-->
<property>
<name>hbase.hstore.compaction.min.size</name>
<va1ue>134217728</value>
</property>
<!--默认值为LONG.MAX_VALUE,表示文件大小大于该值的store file一定会被minor compaction排除-->
<property>
<namezhbase.hstore.compaction.max.size</name>
<va1ue>9223372036854775807</value>
</property>
触发条件
■memstore flush
在进行memstore flush前后都会进行判断是否触发compact
■定期检查线程
周期性检查是否需要进行compaction操作,由参数: hbase.server .thread.wakefrequency决定,默认值是10000 millseconds(10秒)
major compact大合并
■合并Store中所有的HFile为一个HFile
这个过程有删除标记的数据会被真正移除,同时超过单元格maxVersion的版本记录也会被删除。合并频率比较低,默认7
天执行一次, 并且性能消耗非常大,建议生产关闭(设置为0),在应用空闲时间手动触发。一般可以是手动控制进行合并,防
止出现在业务高峰期。
■major compaction触发时间条件
<1--默认值为7天进行一次大合并,-->
<property>
<name>hbase.hregion.majorcompaction</name>
<value>604800000</value>
</property>
■手动触发(在hbase shell中设置)
##便用major_compact命令
major_compact tab1eName
第4节Regionr拆分机制
Region中存储的是大量的rowkey数据,当Region中的数据条数过多的时候,直接影响查询效率.当Region过大的时候.HBase会拆分
Region,这也是Hbase的一个优点.
4.1拆分策略
HBase的Region Split策略一共有以下几种:
1) ConstantSizeRegionSplitPolicy
0.94版本前默认切分策略:
当region大小大于某个阔值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region等 分为2个region。
但是在生产线上这种切分策略却有相当大的弊端,切分策略对于大表和小表没有明显的区分。阈值(hbase.hregion.max.filesize)设置较
大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,这对业务来说并不是什么好事。如果设置较小则对小表友好,但
一个大表就会在整个集群产生大量的region.这对于集群的管理、资源使用、failover来说都不是一件好事。
2) IncreasingToUpperBoundRegionSplitPolicy
0.94版本-2.0版本默认切分策略:
切分策略稍微有点复杂,总体看和ConstantsizeRegionSplitPolicy思路相同,一个region大小大于设置闭值就会触发切分。但是这个闭
值并不像ConstantsizeRegionSplitPolicy是一个固定的值,而是会在一定条件下不断调整,调整规则和region所属表在当前
regionserver上的region个数有关系。
region split的计算公式是:
regioncount^3*128M*2.当region达到该size的时候进行split
例如。
第一次split: 1八3由256。256MB
第二次split: 2A3白256 = 2048MB
第三次split,3^3★256 = 6912MB
第四次split: 4A3曲256 = 16384MB > 10GB, 因此取较小的值10GB
后面每次split的size都是10GB了
3) SteppingSplitPolicy
2.0版本默认切分策略:
这种切分策略的切分闭值又发生了变化,相比IncreasingToupperBoundRegionSplitPolicy简单了一些,依然和待分裂region所属表
在当前regionserver上的region个数有关系,如果region个数等于1.
切分阈值为flush size*2,否则为MaxRegionFilesize. 这种切分策略对于大集群中的大表、小表会比
Increas ingToupperBoundRegionSplitPolicy更加友好,小表不会再产生大量的小region, 而是适可而止。
4) KeyPrefixRegionSplitPolicy
根据rowKey的前綴对数据进行分组,这里是指定rowKey的前多少位作为前缀,比如rowKey都是16位的, 指定前5位是前绿,那么前5位相同的
rowKey在进行region split的时候会分到相同的region中。
5) DelimitedKeyPrefixRegionSplitPolicy
保证相同前缀的数据在同一个region中,例如rowkey的格式为,userid.eventtype.eventid, 指定的delimiter为 _ , 则split的时
候会确保userid相同的数据在同一个region中。
6) DisabledRegionSplitPolicy
不启用自动拆分,需要指定手动拆分
4.2 RegionSplitPolicy的应用
Region拆分策略可以全局统-配置,也可以为单独的表指定拆分策略。
1)通过hbase site.xml全局统- -配置(对hbase所有表生效
<property>
<name>hbase.regionserver.region.split.policy</name>
<value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property>
2)通过Java API为单独的表指定Region拆分策略
HTableDescriptor tableDesc = new HTableDescriptor("test1");
tableDesc.setvalue(HTableDescriptor.SPLIT POLICY,Increas ingToupperBoundRegionsplitpolicy.class.getName());
tableDesc.addFami1y(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);
3)通过HBase Shelli为单个表指定Region拆分策略
hbase> create 'test1', {METADATA => {'SPLIT POLICY' => 'org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy'}},{NAME => 'cf1'}
第5节HBase表的预分区(region)
5.1为何要预分区?
当一个table刚被创建的时候,Hbase默认的分配一个region给table. 也就是说这个时候,所有的读写请求都会访问到同一个
regionServer的同一个region中,这个时候就达不到负载均衡的效果了,集群中的其他regionServer就可能会处于比较空闲的状态。解决
这个问题可以用pre-slitting,在创建table的时候就配置好,生成多个region.
●增加数据读写效率
●负载均衡,防止数据倾斜
●方便集群容灾调度region
每一个region维护着startRow与endRowKey,如果加入的数据符合某个region维护的rowKey范围,则该数据交给这个region维护
5.2手动指定预分区
create ‘person’ ,‘info1’,‘info2’,SPLITS => [‘1000’,‘2000’,‘3000’]
也可以把分区规则创建于文件中
vim split. txt
文件内容
aaa
bbb
ccc
ddd
执行:create ‘student’,‘info’,SPLITS_FILE=> ‘/usr/local/hbase/split.txt’
第6节Region合并
6.1 Region合并说明
Region的合并不是为了性能,而是出于维护的目的。
6.2如何进行Region合并
通过Merge类冷合并Region:【需要先关闭hbase集群】
●需要先关闭hbase集群
●需求:需要把student表中的2个region数据进行合并: student,1593244870695.10c2df60e567e73523a633f20866b4b5.
student,1000,1593244870695.0a4c3ff30a98f79ff6c1e4cc927b3d0d.
这里通过org.apache.hadoop.hbse.util.Merge类来实现,不需要进入hbase shell,直接执行【需要先关闭hbase集群】 :
hbase org.apache.hadoop.hbase.util.Merge student
student,1624244489129.1ff17e7c4f24796db4234d50782b4bb0.
student,aaa,1624244489129.da1da2bb543258cc1f9b21090a8634f7.
通过online. merge热合并Region
●不需要关闭hbase集群,在线进行合并
与冷合并不同的是,online.merge的传参是Region的hash值,而Region的hash值就是Region名称的最后那段在两个,之间的字符串部分。
需求,需要把lagou_s表中的2个region数据进行合并。
student,,1624244489129.1ff17e7c4f24796db4234d50782b4bb0.\
student,aaa,1624244489129.da1da2bb543258cc1f9b21090a8634f7.
需要进入hbase she11:
merge_region '1ff17e7c4f24796db4234d50782b4bb0','da1da2bb543258cc1f9b21090a8634f7'
第2节Hbase 协处理器
2.1协处理器概述
官方地址:http://hbase.apache.org/book.html#cp
访问HBase的方式是使用scan或get获取数据,在获取到的数据上进行业务运算。但是在数据量非常大的时候,比如一个有上亿行及十
万个列的数据集,再按常用的方式移动获取数据就会遇到性能问题。客户端也需要有强大的计算能力以及足够的内存来处理这么多的数据。
此时就可以考虑使用Coprocessor(协处理器)。将业务运算代码封装到Coprocessor中并在RegionServer上运行,即在数据实际存储位置
执行,最后将运算结果返回到客户端。利用协处理器,用户可以编写运行在HBase Server端的代码。
Hbase Coprocessor类似以下概念:
触发器和存储过程: 一个Observer Coprocessor有些类似于关系型数据库中的触发器,通过它我们可以在一些事件 (如Get或是Scan) 发
生前后执行特定的代码。Endpoint Coprocessor则类似于关系型数据库中的存储过程,因为它允许我们在RegionServer.上直接对它存储
的数据进行运算,而非是在客户端完成运算。
MapReduce: MapReduce的原则就是将运算移动到数据所处的节点。Coprocessor也是按照相同的原则去工作的.
AOP:如果熟悉AOP的概念的话,可以将Coprocessor的执行过程视为在传递请求的过程中对请求进行了拦截,并执行了一些自定义代
Observer
协处理器与触发器(rigger)类似:在一些特定事件发生时回调函数 (也被称作钩子函数,hook) 被执行。这些事件包括一些用户产生的
事件,也包括服务器端内部自动产生的事件。
协处理器框架提供的接口如下
RegionObserver:用户可以用这种的处理器处理数据修改事件,它们与表的region联系紧密。
MasterObserver:可以被用作管理或DDL类型的操作,这些是集群级事件。
WALObserver:提供控制WAL的钩子函数
Endpoint
这类协处理器类似传统数据库中的存储过程,客户端可以调用这些Endpoint协处理器在Regionserver中执行一段代码,并将
RegionServer端执行结果返回给客户端进一步处理。
Endpoint常见用途
聚合操作
假设需要找出一张表中的最大数据,即max聚合操作,普通做法就是必须进行全表扫描,然后Client代码内遍历扫描结果,并执行求最
大值的操作。这种方式存在的弊端是无法利用底层集群的并发运算能力,把所有计算都集中到Client端执行,效率低下。
使用Endpoint Coprocessor,用户可以将求最大值的代码部署到HBase RegionServer端,HBase 会利用集群中多个节点的优势来并
发执行求最大值的操作。也就是在每个Region范围内执行求最大值的代码,将每个Region的最大值在Region Server端计算出,仅仅
将该max值返回给Client.在Client进一 步将多个 Region的最大值汇总进一步找到全局的最大值。
Endpoint Coprocessor的应用我们后续可以借助于Phoenix非常容易就能实现。针对Hbase数据集进行聚合运算直接使用SQL语句就能搞定。
第4节HBase表的RowKey设计
2.1 RowKey长度原则
rowkey是一个二进制码流,可以是任意字符串,最大长度64kb,实际应用中-般为10-100bytes, 以byte[形式保存,- 般设计成定长.
●建议越短越好,不要超过16个字节
设计过长会降低memstore内存的利用率和HFile存储数据的效率。
2.2 RowKey散列原则
建议将rowkey的高位作为散列字段,这样将提高数据均街分布在每个RegionServer,以实现负载均衡的几率。
2.3 RowKey唯-原则
必须在设计上保证其唯一性,
访问hbase table中的行:有3种方式:
●单个rowkey
●rowkey 的range I
●全表扫描(一定要避免全表扫描)
实现方式:
1) org.apache.hadoop.hbase.client.Get
2) scan方法: org.apache.hadoop.hbase.client.Scan
scan使用的时候注意:
setStartRow, setEndRow 限定范围,范围越小,性能越高。
2.4 RowKey排序原则
HBase的Rowkey是按照ASCII有序设计的,我们在设计Rowkey时要充分利用这点
第5节HBase表的热点
5.1什么是热点.
检索habse的记录首先要通过row key来定位数据行。当大量的client访问hbase集群的一个或少数几个节点,造成少数region server的
读/写请求过多、负载过大,而其他region server负载却很小,就造成了"热点"现象
5.2热点的解决方案
●预分区
预分区的目的让表的数据可以均衡的分散在集群中,而不是默认只有一个region分布在集群的一个节点上。
●加盐
这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数[具体就是给rowkey分配-个随机前缀以使得它和之前的rowkey的开头不同。
●哈希
哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重
构完整的rowkey.可以使用get操作准确获取某一个行数据。
●反转
反转固定长度或者数字格式的ronkey.这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随
机rowkEy,但是牺牲了rowkey的有序性。
第6节HBase的二级索引
HBase表按照rowkey查询性能是最高的。rowkey就相当于hbase表的一级索引! !
为了HBase的数据查询更高效、适应更多的场景,诸如使用非rowkey字段检索也能做到秒级响应,或者支持各个字段进行模糊查询
和多字段组合查询等,因此需要在HBase 上面构建二级索引, 以满足现实中更复杂多样的业务需求。
hbase的二级索引其本质就是建立hbase表中列与行键之间的映射关系。
常见的二级索引我们一般可以借助各种其他的方式来实现,例如Phoenix或者solr或者ES等
回第7节布隆过滤器在hbase的应用
●布隆过滤器应用
之前再讲hbase的数据存储原理的时候,我们知道hbase的读操作需要访问大量的文件,大部分的实现通过布隆过滤器来避免大量的读文件操作。
●布隆过滤器的原理
通常判断某个元索是否存在用的可以选择hashmap.但是HashMap的实现也有缺点,例如存储容量占比高,考虑到负载因子的存
在,通常空间是不能被用满的,而一旦你的值很多例如上亿的时候,那HashMap占据的内存大小就变得很可观了。
Bloom Filter是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示-个集合,并能判断-个元索是否属于这个集合。I
hbase中布隆过滤器来过滤指定的rowkey是否在目标文件,避免扫描多个文件。使用布隆过滤器来判断。
布隆过滤器返回true,在结果不一定争取,.如果返回false则说明确实不存在。