Hbase-- 03

news2024/9/25 23:16:56

4.原理加强

4.1数据存储

4.1.1行式存储

传统的行式数据库将一个个完整的数据行存储在数据页中

4.1.2列式存储

列式数据库是将同一个数据列的各个值存放在一起

传统行式数据库的特性如下:
 ①数据是按行存储的。
 ②没有索引的查询使用大量I/O。比如一般的数据库表都会建立索引,通过索引加快查询效率。
 ③建立索引和物化视图需要花费大量的时间和资源。
 ④面对查询需求,数据库必须被大量膨胀才能满足需求。

列式数据库的特性如下:
 ①数据按列存储,即每一列单独存放。
 ②数据即索引。
 ③只访问查询涉及的列,可以大量降低系统I/O
 ④每一列由一个线程来处理,即查询的并发处理性能高。
 ⑤数据类型一致,数据特征相似,可以高效压缩。比如有增量压缩、前缀压缩算法都是基于列存储的类型定制的,所以可以大幅度提高压缩比,有利于存储和网络输出数据带宽的消耗。

4.1.3列族式存储

列族式存储是一种非关系型数据库存储方式,按列而非行组织数据。它的数据模型是面向列的,即把数据按照列族的方式组织,将属于同一列族的数据存储在一起。每个列族都有一个唯一的标识符,一般通过列族名称来表示。它具有高效的写入和查询性能,能够支持极大规模的数据

  • 如果一个表有多个列族, 每个列族下只有一列, 那么就等同于列式存储。
  • 如果一个表只有一个列族, 该列族下有多个列, 那么就等同于行式存储.

4.1.4hbase的存储路径:

在conf目录下的hbase-site.xml文件中配置了数据存储的路径在hdfs上

XML
<property>
<name>hbase.rootdir</name>
<value>hdfs://linux01:8020/hbase</value>
</property>

hdfs上的存储路径:

4.2region

Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。
Region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。

4.2.1region的分配

一个表中可以包含一个或多个Region。

每个Region只能被一个RS(RegionServer)提供服务,RS可以同时服务多个Region,来自不同RS上的Region组合成表格的整体逻辑视图。

regionServer其实是hbase的服务,部署在一台物理服务器上,region有一点像关系型数据的分区,数据存放在region中,当然region下面还有很多结构,确切来说数据存放在memstore和hfile中。我们访问hbase的时候,先去hbase 系统表查找定位这条记录属于哪个region,然后定位到这个region属于哪个服务器,然后就到哪个服务器里面查找对应region中的数据

4.2.2region结构

4.2.3数据的写入

4.2.4Memstore Flush流程

flus流程分为三个阶段:

  1. prepare阶段:遍历当前 Region中所有的 MemStore ,将 MemStore 中当前数据集 CellSkpiListSet 做一个快照 snapshot;然后再新建一个 CellSkipListSet。后期写入的数据都会写入新的 CellSkipListSet 中。prepare 阶段需要加一把 updataLock 对写请求阻塞,结束之后会释放该锁。因为此阶段没有任何费时操作,因此锁持有时间很短
  1. flush阶段:遍历所有 MemStore,将 prepare 阶段生成的snapshot 持久化为临时文件,临时文件会统一放到目录.tmp下。这个过程因为涉及到磁盘 IO 操作,因此相对耗时
  1. commit阶段:遍历所有 MemStore,将flush阶段生成的临时文件移动到指定的 ColumnFamily 目录下,针对 HFile生成对应的 StoreFile 和 Reader,把 StoreFile 添加到 HStore 的 storefiles 列表中,最后再清空 prepare 阶段生成的 snapshot快照

4.2.5Compact 合并机制

hbase中的合并机制分为自动合并和手动合并

4.2.5.1自动合并:

  • minor compaction 小合并
  • major compacton 大合并

minor compaction(小合并)

将 Store 中多个 HFile 合并为一个相对较大的 HFile 过程中会选取一些小的、相邻的 StoreFile 将他们合并成一个更大的 StoreFile,对于超过 TTL 的数据、更新的数据、删除的数据仅仅只是做了标记,并没有进行物理删除。一次 minor compaction 过后,storeFile会变得更少并且更大,这种合并的触发频率很高

4.2.5.1.1小合并的触发方式:

memstore flush会产生HFile文件,文件越来越多就需要compact.每次执行完Flush操作之后,都会对当前Store中的文件数进行判断,一旦文件数大于配置3,就会触发compaction。compaction都是以Store为单位进行的,而在Flush触发条件下,整个Region的所有Store都会执行compact

后台线程周期性检查

检查周期可配置:

hbase.server.thread.wakefrequency/默认10000毫秒)*hbase.server.compactchecker.interval.multiplier/默认1000

CompactionChecker大概是2hrs 46mins 40sec 执行一次

XML
<!--表示至少需要三个满足条件的store file时,minor compaction才会启动-->
<property>
        <name>hbase.hstore.compactionThreshold</name>
        <value>3</value>
</property>

<!--表示一次minor compaction中最多选取10个store file-->
<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>

<!--默认值为LONG.MAX_VALUE,表示文件大小大于该值的store file 一定会被minor compaction排除-->
<property>
        <name>hbase.hstore.compaction.max.size</name>
        <value>9223372036854775807</value>
</property>

4.2.5.1.2major compaction(大合并)

合并 Store 中所有的 HFile 为一个 HFile,将所有的 StoreFile 合并成为一个 StoreFile,这个过程中还会清理三类无意义数据:被删除的数据、TTL过期数据、版本号超过设定版本号的数据。合并频率比较低,默认7天执行一次,并且性能消耗非常大,建议生产关闭(设置为0),在应用空间时间手动触发。一般是可以手动控制进行合并,防止出现在业务高峰期。

XML
线程先检查小文件数是否大于配置3,一旦大于就会触发compaction。
大文件周期性合并成Major Compaction
如果不满足,它会接着检查是否满足major compaction条件
如果当前store中hfile的最早更新时间早于某个值mcTime就会触发major compaction
(默认7天触发一次,可配置手动触发)

<!--默认值为7天进行一次大合并,-->
<property>
        <name>hbase.hregion.majorcompaction</name>
        <value>604800000</value>
</property>

4.2.5.2手动合并

一般来讲,手动触发compaction通常是为了执行major compaction,一般有这些情况需要手动触发合并是因为很多业务担心自动maior compaction影响读写性能,因此会选择低峰期手动触发也有可能是用户在执行完alter操作之后希望立刻生效,执行手动触发maiorcompaction:

造数据

Shell
truncate 'doit:test'                                
put 'doit:test','001','f1:name','zss'
put 'doit:test','002','f1:name','zss'
put 'doit:test','003','f1:name','zss'
put 'doit:test','004','f1:name','zss'
flush 'doit:test'                   
put 'doit:test','005','f1:name','zss'
put 'doit:test','006','f1:name','zss'
put 'doit:test','007','f1:name','zss'
put 'doit:test','008','f1:name','zss'
flush 'doit:test'                   
put 'doit:test','009','f1:name','zss'
put 'doit:test','010','f1:name','zss'
put 'doit:test','011','f1:name','zss'
put 'doit:test','012','f1:name','zss'
flush 'doit:test'
put 'doit:test','013','f1:name','zss'
put 'doit:test','014','f1:name','zss'
put 'doit:test','015','f1:name','zss'
put 'doit:test','016','f1:name','zss'
flush 'doit:test'
put 'doit:test','017','f1:name','zss'
put 'doit:test','018','f1:name','zss'
put 'doit:test','019','f1:name','zss'
put 'doit:test','020','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','025','f1:name','zss'
put 'doit:test','026','f1:name','zss'
put 'doit:test','027','f1:name','zss'
put 'doit:test','028','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'
put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'

put 'doit:test','021','f1:name','zss'
put 'doit:test','022','f1:name','zss'
put 'doit:test','023','f1:name','zss'
put 'doit:test','024','f1:name','zss'
flush 'doit:test'


每次flush一下都会在底层生成一个小文件

Shell
##使用major_compact命令
major_compact tableName

major_compact 'doit:test'

4.2.6region的拆分

region中存储的是一张表的数据,当region中的数据条数过多的时候,会直接影响查询效率。当region过大的时候,region会被拆分为两个region,HMaster会将分裂的region分配到不同的regionserver上,这样可以让请求分散到不同的RegionServer上,已达到负载均衡  , 这也是HBase的一个优点

4.2.6.1region的拆分策略

1. ConstantSizeRegionSplitPolicy0.94版本前,HBase region的默认切分策略

region中最大的store大小超过某个阈值(hbase.hregion.max.filesize=10G)之后就会触发切分,一个region等分为2region

但是在生产线上这种切分策略却有相当大的弊端(切分策略对于大表和小表没有明显的区分):

  • 阈值(hbase.hregion.max.filesize)设置较大对大表比较友好,但是小表就有可能不会触发分裂,极端情况下可能就1个,形成热点,这对业务来说并不是什么好事。
  • 如果设置较小则对小表友好,但一个大表就会在整个集群产生大量的region,这对于集群的管理、资源使用、failover来说都不是一件好事。

2. IncreasingToUpperBoundRegionSplitPolicy0.94版本~2.0版本默认切分策略

总体看和ConstantSizeRegionSplitPolicy思路相同,一个region中最大的store大小大于设置阈值就会触发切分。 但是这个阈值并不像ConstantSizeRegionSplitPolicy是一个固定的值,而是会在一定条件下不断调整,调整规则和region所属表在当前regionserver上的region个数有关系.

region split阈值的计算公式是:

  • regioncount:是region所属表在当前regionserver上的region的个数
  • 阈值 = regioncount^3 * 128M * 2,当然阈值并不会无限增长,最大不超过MaxRegionFileSize10G),region中最大的store的大小达到该阈值的时候进行region split

例如:

  • 第一次split阈值 = 1^3 * 256 = 256MB
  • 第二次split阈值 = 2^3 * 256 = 2048MB
  • 第三次split阈值 = 3^3 * 256 = 6912MB
  • 第四次split阈值 = 4^3 * 256 = 16384MB > 10GB,因此取较小的值10GB
  • 后面每次splitsize都是10GB

特点

  • 相比ConstantSizeRegionSplitPolicy,可以自适应大表、小表;
  • 在集群规模比较大的情况下,对大表的表现比较优秀
  • 对小表不友好,小表可能产生大量的小region,分散在各regionserver
  • 小表达不到多次切分条件,导致每个split都很小,所以分散在各个regionServer

3. SteppingSplitPolicy2.0版本默认切分策略

相比 IncreasingToUpperBoundRegionSplitPolicy 简单了一些  region切分的阈值依然和待分裂region所属表在当前regionserver上的region个数有关系

  • 如果region个数等于1,切分阈值为flush size 128M * 2
  • 否则为MaxRegionFileSize

这种切分策略对于大集群中的大表、小表会比 IncreasingToUpperBoundRegionSplitPolicy 更加友好,小表不会再产生大量的小region,而是适可而止。

4. KeyPrefixRegionSplitPolicy

根据rowKey的前缀对数据进行分区,这里是指定rowKey的前多少位作为前缀,比如rowKey都是16位的,指定前5位是前缀,那么前5位相同的rowKey在相同的region

5. DelimitedKeyPrefixRegionSplitPolicy

保证相同前缀的数据在同一个region中,例如rowKey的格式为:userid_eventtype_eventid,指定的delimiter _ ,则split的的时候会确保userid相同的数据在同一个region中。 按照分隔符进行切分,而KeyPrefixRegionSplitPolicy是按照指定位数切分

6. BusyRegionSplitPolicy

按照一定的策略判断Region是不是Busy状态,如果是即进行切分

如果你的系统常常会出现热点Region,而你对性能有很高的追求,那么这种策略可能会比较适合你。它会通过拆分热点Region来缓解热点Region的压力,但是根据热点来拆分Region也会带来很多不确定性因素,因为你也不知道下一个被拆分的Region是哪个

7. DisabledRegionSplitPolicy:不启用自动拆分, 需要指定手动拆分

4.2.6.2手动合并拆分region

手动合并

Shell
hbase(main):025:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684205468848.920ae3e043ad95890c4f5693cb663bc5. |            | rowkey_010 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_010,1684207066858.5e04eb75e5510ad65a0f3001de3c7aa0. | rowkey_010 | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207066858.ed1b328ca4c485d4fa429922f6c18f0b. | rowkey_015 | rowkey_020 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_020,1684205468848.25d62e8cc2fdaecec87234b8d28f0827. | rowkey_020 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 6 rows
Took 0.0299 seconds                                                                                                                                                    
hbase(main):026:0> merge_region 'doit:test,,1684205468848.920ae3e043ad95890c4f5693cb663bc5.','doit:test,rowkey_010,1684207066858.5e04eb75e5510ad65a0f3001de3c7aa0.'
Took 1.2638 seconds                                                                                                                                                   
hbase(main):027:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684207066859.cdc1226d634c0cf16f58832637f485b6. |            | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207066858.ed1b328ca4c485d4fa429922f6c18f0b. | rowkey_015 | rowkey_020 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_020,1684205468848.25d62e8cc2fdaecec87234b8d28f0827. | rowkey_020 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 5 rows
Took 0.0271 seconds

手动拆分

Shell
hbase(main):029:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux03,16020,1684200651855 |           doit:test,,1684207066860.8ebf4555c58bd0e5fedae5d4efbe4235. |            | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 3 rows
Took 0.0329 seconds                                                                                                                                                   
hbase(main):030:0> split 'doit:test,,1684207066860.8ebf4555c58bd0e5fedae5d4efbe4235.','rowkey_025'
Took 0.1179 seconds                                                                                                                                                   
hbase(main):031:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux02,16020,1684200651886 |           doit:test,,1684207502853.af0819bd7f6daa9db2a8f994fb41682d. |            | rowkey_025 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_025,1684207502853.80d7feace447978ffe4a54418a20afd0. | rowkey_025 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 4 rows
Took 0.0179 seconds                                                                                                                                                    
hbase(main):032:0> split 'doit:test,,1684207502853.af0819bd7f6daa9db2a8f994fb41682d.','rowkey_015'
Took 0.1262 seconds                                                                                                                                                    
hbase(main):033:0> list_regions 'doit:test'
                 SERVER_NAME |                                                          REGION_NAME |  START_KEY |    END_KEY |  SIZE |   REQ |   LOCALITY |
 --------------------------- | -------------------------------------------------------------------- | ---------- | ---------- | ----- | ----- | ---------- |
 linux02,16020,1684200651886 |           doit:test,,1684207546572.0f550ec8fa1af0ab9e73032d224d9f00. |            | rowkey_015 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_015,1684207546572.09a2022c54dfef68866ac73e3f78bc70. | rowkey_015 | rowkey_025 |     0 |     0 |        0.0 |
 linux02,16020,1684200651886 | doit:test,rowkey_025,1684207502853.80d7feace447978ffe4a54418a20afd0. | rowkey_025 | rowkey_030 |     0 |     0 |        0.0 |
 linux03,16020,1684200651855 | doit:test,rowkey_030,1684205468848.2b0468e6643b95159fa6e210fa093e66. | rowkey_030 | rowkey_040 |     0 |     0 |        0.0 |
 linux01,16020,1684205091382 | doit:test,rowkey_040,1684205468848.fb12c09c7c73cfeff0bf79b5dda076cb. | rowkey_040 |            |     0 |     0 |        0.0 |
 5 rows
Took 0.0241 seconds 

4.2.7bulkLoad实现批量导入

bulkloader 一个用于批量快速导入数据到hbase的工具/方法

用于已经存在一批巨量静态数据的情况!如果不用bulkloader工具,则只能用rpc请求,一条一条地通过rpc提交给regionserver去插入,效率极其低下

4.2.7.1原理

相比较于直接写HBase,BulkLoad主要是绕过了写WAL日志这一步,还有写Memstore和Flush到磁盘,从理论上来分析性能会比Put快!

4.2.7.2BulkLoad实战示例1importTsv工具

原理:

Importtsvhbase自带的一个 csv文件--HFile文件 的工具,它能将csv文件转成HFile文件,并发送给regionserver。它的本质,是内置的一个将csv文件转成hfile文件的mr程序!

案例演示:

Shell
CSV转HFILE的命令示例如下:
// 001,北戴河,河北省,河北省北戴河昌平区沙河镇赋腾国际创客中心A座4018室
hbase  org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator=, \
-Dimporttsv.columns='HBASE_ROW_KEY,f:city,f:province,x:address'  \
-Dimporttsv.bulk.output=/tsv/output \
user_info \
/tsv/input

ImportTsv命令的参数说明如下:

-Dimporttsv.skip.bad.lines=false - 若遇到无效行则失败

-Dimporttsv.separator=, - 使用特定分隔符,默认是tab也就是\t

-Dimporttsv.timestamp=currentTimeAsLong - 使用导入时的时间戳

-Dimporttsv.mapper.class=my.Mapper - 使用用户自定义Mapper类替换TsvImporterMapper

-Dmapreduce.job.name=jobName - 对导入使用特定mapreduce作业名

-Dcreate.table=no - 避免创建表,注:如设为为no,目标表必须存在于HBase

-Dno.strict=true - 忽略HBase表列族检查。默认为false

-Dimporttsv.bulk.output=/user/yarn/output 作业的输出目录

示例演示:

Plain Text
创建一张表:
hbase(main):005:0> create 'doit:user_info1','f1','f2'
Created table doit:user_info1
Took 1.4252 seconds                                                                                               
=> Hbase::Table - doit:user_info1
hbase(main):006:0>

准备文件:
rowkey_001,zss,18,male,chengxuyuan,beijing
rowkey_002,lss,28,male,jinrongdalao,shanghai
rowkey_003,liuyan,18,female,yanyuan,beijing
rowkey_004,tanyang,38,female,yanyuan,shanghai


上传文件至hdfs上
[root@linux01 data]# hdfs dfs -mkdir -p /tsv/input
[root@linux01 data]# hdfs dfs -put hbase.txt /tsv/input/
[root@linux01 data]#



使用importtsv将测试文件转为hfile
hbase org.apache.hadoop.hbase.mapreduce.ImportTsv \
-Dimporttsv.separator=, \
-Dimporttsv.columns='HBASE_ROW_KEY,f1:name,f1:age,f1:gender,f2:job,f2:address' \
-Dimporttsv.bulk.output=/uu/output \
doit:user_info1 \
/tsv/input/hbase.txt



将hfile注入hbase
hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /uu/output/  doit:user_info1


查看表中的数据
hbase(main):067:0> scan 'doit:user_info1'
ROW                           COLUMN+CELL                                                                          
 rowkey_001                   column=f1:age, timestamp=1684062601474, value=18                                    
 rowkey_001                   column=f1:gender, timestamp=1684062601474, value=male                               
 rowkey_001                   column=f1:name, timestamp=1684062601474, value=zss                                  
 rowkey_001                   column=f2:address, timestamp=1684062601474, value=beijing                           
 rowkey_001                   column=f2:job, timestamp=1684062601474, value=chengxuyuan                           
 rowkey_002                   column=f1:age, timestamp=1684062601474, value=28                                    
 rowkey_002                   column=f1:gender, timestamp=1684062601474, value=male                               
 rowkey_002                   column=f1:name, timestamp=1684062601474, value=lss                                  
 rowkey_002                   column=f2:address, timestamp=1684062601474, value=shanghai                          
 rowkey_002                   column=f2:job, timestamp=1684062601474, value=jinrongdalao                          
 rowkey_003                   column=f1:age, timestamp=1684062601474, value=18                                     
 rowkey_003                   column=f1:gender, timestamp=1684062601474, value=female                             
 rowkey_003                   column=f1:name, timestamp=1684062601474, value=liuyan                               
 rowkey_003                   column=f2:address, timestamp=1684062601474, value=beijing                           
 rowkey_003                   column=f2:job, timestamp=1684062601474, value=yanyuan                               
 rowkey_004                   column=f1:age, timestamp=1684062601474, value=38                                    
 rowkey_004                   column=f1:gender, timestamp=1684062601474, value=female                             
 rowkey_004                   column=f1:name, timestamp=1684062601474, value=tanyang                              
 rowkey_004                   column=f2:address, timestamp=1684062601474, value=shanghai                          
 rowkey_004                   column=f2:job, timestamp=1684062601474, value=yanyuan                                
4 row(s)
Took 0.0587 seconds         

4.3hfile

4.3.1逻辑数据组织格式:

  • Scanned block section表示顺序扫描HFile时(包含所有需要被读取的数据)所有的数据块将会被读取,包括Leaf Index Block和Bloom Block;
  • Non-scanned block sectionHFile顺序扫描的时候该部分数据不会被读取,主要包括Meta Block和Intermediate Level Data Index Blocks两部分;
  • Load-on-open-section这部分数据在HBase的region server启动时,需要加载到内存中。包括FileInfo、Bloom filter block、data block index和meta block index等各种索引的元数据信息;
  • Trailer这部分主要记录了HFile的基本信息、各个部分的偏移值和寻址信息。
  • Data Block主要存储用户的key,value信息
  • Meta Block记录布隆过滤器的信息
  • Root Data IndexDataBlock的根索引以及MetaBlock和Bloom Filter的索引
  • Intermediate Level Index:DataBlock的第二层索引
  • Leaf Level IndexDataBlock的第三层索引,即索引数的叶子节点
  • Fileds for midKey:这部分数据是Optional的,保存了一些midKey信息,可以快速地定位到midKey,常常在HFileSplit的时候非常有用
  • MetaIndex:即meta的索引数据,和data index类似,但是meta存放的是BloomFilter的信息
  • FileInfo:保存了一些文件的信息,如lastKey,avgKeylen,avgValueLen等等
  • Bloom filter metadata:是布隆过滤器的索引

4.3.2物理数据结构图:

4.3.3数据的读取

  1. Client访问zookeeper,获取hbase:meta所在RegionServer的节点信息
  1. Client访问hbase:meta所在的RegionServer,获取hbase:meta记录的元数据后先加载到内存中,然后再从内存中根据需要查询的RowKey查询出RowKey所在的Region的相关信息(Region所在RegionServer)
  1. Client访问RowKey所在Region对应的RegionServer,发起数据读取请求
  1. 读取memstore中的数据,看是否有key对应的value的值
  1. 不管memstore中有没有值,都需要去读取Hfile中的数据(再读取Hfile中首先通过索引定位到data block)
  1. 判断cache block中中是否已经加载过需要从文件中读取的bloom block和data block,如果加载过了,就直接读取cache block中的数据,如果没有,就读取文件中的block数据
  1. 将memstore和Hfile中读取的数据汇总取正确的数据返回给客户端

4.4rowkey的设计

4.4.1设计的三大原则

  1. Rowkey长度原则

Rowkey是一个二进制码流,Rowkey的长度被很多开发者建议设计在10-100个字节,不过建议是越短越好,不要超过16个字节

原因如下:

  • 数据的持久化文件HFile中是按照KeyValue存储的,如果Rowkey过长比如100个字节,1000万列数据光Rowkey就要占用100*1000万=10亿个字节,将近1G数据,这会极大影响Hfile的存储效率;
  • MemStore将缓存部分数据到内存,如果Rowkey字段过长内存的有效利用率降低,系统将无法缓存更多的数据,这会降低检索效率,因此Rowkey的字节长度越短越好。
  • 目前操作系统一般都是64位系统,内存8字节对齐,空值在16个字节,8字节的整数倍利用操作系统的最佳特性。
  1. Rowkey散列原则

如果Rowkey是按时间戳的方式递增,因为rowkey是按照字典顺序排序的,这样会出现大量的数据插入到一个reion中,而其他的region相对比较空闲从而造成热点问题,所以尽量不要将开头相同的内容作为rowkey造成热点问题,可以将时间戳反转后在作为rowkey。

  1. Rowkey唯一原则

必须在设计Rowkey上保证其唯一性。否则前面插入的数据将会被覆盖。

4.4.2常见的避免热点的方法以及它们的优缺点

加盐

这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。

哈希

哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据

反转

第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。

比如手机号的反转,时间戳的反转,当一个连续递增的数字类型想要作为rowkey时,可以用一个很大的数去减这个rowkey,反转后再当成rowkey

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638084.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3 element-plus后台管理系统实现登录与记住密码功能

一、效果 二、代码部分 1、勾选记住密码布局代码 2、判断是否勾选&#xff0c;勾选则保存账号密码&#xff0c;否则不保存账号密码&#xff0c;由于是demo,故并没有做加密&#xff0c;如果是生成最好是对密码做加密处理。 3、页面挂载的时候需要背叛的是否保存密码&#xff0c;…

JDK8 ConcurrentHashMap 怎么放弃 Lock 使用 synchronized 了

synchronized 之前一直都是重量级锁&#xff0c;但是 JDK6 中官方是对他进行过升级&#xff0c;引入了偏向锁&#xff0c;轻量级锁&#xff0c;重量级锁&#xff0c;现在采用的是锁升级的方式去做的。针对synchronized 获取锁的方式&#xff0c;JVM 使用了锁升级的优化方式&…

十行代码,就能真正让你理解DMA(CPU的秘书)

下面的代码是单片机串口发送数据的程序. char a0xAA;//定义变量a,值为0xAA&#xff1b; TXREG a;//把数据由内存转移到串口外设&#xff1b;那我们定义的变量a的值存储在哪里了呢&#xff1f;可以看下单片机的逻辑框图。 变量其实都是存在一个叫SRAM的存储器中&#xff0c;它…

Playwright 和 Selenium 的区别是什么?

前言 最近有不少同学问到 Playwright 和 Selenium 的区别是什么&#xff1f;有同学可能之前学过 selenium 了&#xff0c;再学一个 playwright 感觉有些多余&#xff0c;可能之前有项目已经是 selenium 写的了&#xff0c;换成 playwright 需要时间成本&#xff0c;并且可能有…

【支付系统】核心支付流程

支付在产品中常见的用处为购买和充值.这两种功能操作大相径庭,其中购买相对充值多了很多步骤,它需要锁商品或者库存,还需要超时未支付取消订单等操作.在这篇文章中主要探讨支付部分,属于购买和充值公共部分. 下面是绘制的简易支付时序图 以上时序图并非完整,其实核心步骤就是, …

商城购买会员打折满减优惠券商品

文章目录 前言一、代码结构二、UML图三、代码实现3.1.domain3.2.enums3.3.strategy3.4.service3.5.config 四、单元测试五、模式应用六、问题及优化思路6.1.问题6.2.优化 总结 前言 使用策略模式、工厂方法模式、单例模式实现一些购买策略&#xff0c;需求&#xff1a;商城商品…

服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】

完整源码资料 地址直达&#xff1a;http://t.csdn.cn/RWsGw 前言 这是大二时候写的第一个Java项目&#xff0c;框架基本上都没有用到、而且用到的技术很老很老。只简单使用了一个Mybatis简化数据库的操作。前端框架用的还是Layui&#xff0c;贼难用。闲的无聊&#xff0c;对这…

缺少成本票怎么解决?首选自然人代开,方便又快捷!

《税筹顾问》专注于园区招商&#xff0c;您的贴身节税小能手&#xff0c;合理合规节税&#xff01; 成本票缺失导致的严重结果就是&#xff0c;缺少成本入账&#xff0c;导致利润虚高&#xff0c;企业所得税变高了&#xff0c;那么现有的解决方式很多&#xff0c;只是一些方法过…

图形学实验(完整文件见上传)

CRect rect; this->GetClientRect(rect); pDC->Ellipse(rect); // DDALineView.cpp : implementation of the CDDALineView class // #include “stdafx.h” #include “DDALine.h” #include “DDALineDoc.h” #include “DDALineView.h” #ifdef _DEBUG #define new…

Qt扫盲-QEvent 理论总结

QEvent 理论总结 一、概述二、事件类型1. Qt 已定义类型2. 开放用户定义类型 三、注册事件 一、概述 Qt的主事件循环(QCoreApplication::exec())从事件队列中获取原生窗口系统事件&#xff0c;将它们转换为QEvents&#xff0c;并将转换后的事件发送给QObjects。 一般来说&…

Multimodal fusion via cortical network inspired losses(第一次优质论文分享)

Multimodal fusion via cortical network inspired losses 论文介绍1. 论文研究的任务是什么&#xff1f;2. 论文关注/拟解决的问题是什么&#xff1f;3. 论文提出什么方法如何解决这个问题&#xff1f;4. 如何设计实验 来证明 所提方法确实解决了 拟解决的问题&#xff1f; 论…

Ada Tutorial(2)SPARK Examiner + SPARK Prover

文章目录 代码 Task1.adb代码 task3.adbtask4.adb 在Ada和SPARK中&#xff0c;SPARK_Mode是一个编译指示&#xff0c;它表示随后的代码将使用SPARK语言规则进行编译和分析。 在with SPARK_Mode > On的影响下&#xff0c;编译器会在编译过程中应用SPARK语言规则&#xff0c;它…

基于“声音”的量子计算机 | Science速递

光子盒研究院 现在&#xff0c;一个基于声音的量子计算机关键构件已被首次被证明是有效的。 构建量子计算机的一种流行方式是将信息编码到光粒子的量子状态中&#xff0c;然后将它们送过镜子和透镜等“迷宫”般的设备阵列来操纵这些信息。量子力学定律指出&#xff0c;量子粒子…

关于B/S结构系统的会话session机制

用户打开浏览器&#xff0c;进行一系列操作&#xff0c;然后最终将浏览器关闭&#xff0c;这整个过程叫做一次会话&#xff0c;会话对象叫session 用户在浏览器上点击了一次超链接或按钮等&#xff0c;称为一次请求&#xff0c;java对象是request session机制属于B/S结构的一部…

项目 引入 uView

只分享干货&#xff01; 第一点&#xff1a; npm install uview-ui//或yarn add uview-ui 第二点 import Vue from vue; import uView from uview-ui;Vue.use(uView);//或// main.js import uView from /node_modules/uview-ui Vue.use(uView) 第三点 import /node_module…

RK3568开发板 buildroot配置文件

在上一期技术分享中我们学会了如何在buildroot里选中我们自己想要的软件&#xff0c;如vsftpd、openssh等&#xff0c;那么有些客户可能会有疑问&#xff0c;安装完软件后需要配置相应的环境&#xff0c;应该怎么样默认的配置在系统中呢&#xff1f;其实这里的话已经为大家考虑…

python kafka 指定消费者名字

#!/usr/bin/env python # codingutf-8 """ kafka的消费者不是线程安全的&#xff0c;不能多线程启用 kafka不像其他的MQ&#xff0c;消费完数据&#xff0c;直接丢掉&#xff0c;而是会默认存储7天&#xff0c;存储7天后自动清除&#xff0c;故而可以从…

AI虚拟数字人在医学领域的四大应用场景

AI虚拟数字人技术是一种基于计算机图形学和人工智能技术的新型应用&#xff0c;可以模拟人类的外貌、语言、行为等特征&#xff0c;实现与人类的交互。在医疗领域中&#xff0c;AI虚拟数字人技术也有着广泛的应用前景。以下是几个可能的应用场景&#xff1a; 1.医学教育 AI虚拟…

java poi生成excel折线图、柱状图、饼图、动态列表

实现效果 测试类 public class ChartTest {// 开始行public static int chartRowStart 3;// 结束行public static int chartRowEnd 20;public static ChartPosition chartPosition;public static void main(String[] args) throws IOException {// 填充数据XSSFWorkbook work…

30个Python代码,10分钟get常用技巧!

关注“Python专栏”&#xff0c;搜索暗号【面试大全】立即领取面试题简历模板。 学 Python 怎样才最快&#xff0c;当然是实战各种小项目&#xff0c;只有自己去想与写&#xff0c;才记得住规则。本文是 30 个极简任务&#xff0c;初学者可以尝试着自己实现&#xff1b;本文同样…