HBASE学习

HBASE简介

定义:

基于hdfs的分布式,高可用,非关系型数据库

数据模型部分相关概念:

  1. 命名空间(name space):类似关系型数据库中的库
  2. 行键(row):类似关系型数据库中的行,一般按照字典序排序
  3. 列簇(Column Family):就是一个列族,其内部还可有多个下设列
  4. 列限定符(Column Qualifier):列簇的下设列
  5. 时间戳(Time Stamp):不解释
  6. 信息单元(cell):由行键、列簇、列限定符和时间戳四者唯一确定的单元
  7. column:列族和列限定符的头头(不太准确)

hbase逻辑结构(概念视图)

HBASE学习
补充:

  1. 列族下设的列都称为列限定符。
  2. 后面讲的region其实就是这个逻辑模型中的表按照横向切分,即0001和0002可以做为一个region,也可以0001单独作为一个region,也可以0001、0002、0003一起作为一个region。这个region一定是包括了既定行的所有的列族。
  3. 后续还有一个store的概念,即在region中由于包括了多个列族,store就是region中下设的一个列族的内容,即在region中的一个列族对应一个store。

hbase物理结构

HBASE学习

补充:

  1. hbase中的数据在物理上的存储是一条信息的每个信息单元分别存储,不是一条条的存储。

Hbase进阶

架构原理

HBASE学习

  1. storefile:实际存储数据的文件,其在hdfs上以hfile的形式存在。同时数据在store上时有序的(字典序)
  2. memstore:一个缓存区,数据落盘前先写到memstore,提高效率,同时由于写入时有按照字典序排序的要求,所以可以先在该区进行排序后在写入
  3. wal:日志,数据写入memstore之前先会在wal上写(因为memstore时内存区,数据不安全,容易丢失)这样数据不会丢失,在数据成功落盘后,该此操作在此处写入的数据会被清除。

数据在Hbase上的写入流程

HBASE学习

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

数据在Hbase上的读取流程

HBASE学习

  1. client向zk发起获取元数据所在位置的请求。
  2. zk返回元数据所在regionserver信息给client。
  3. client向元数据所在的regionserver发起获取元数据的请求。
  4. 元数据所在的regionserver返回元数据信息给client,client会缓存元数据,便于下次使用。
  5. client根据元数据得知数据应该到哪个region中读取,该region处于哪个regionserver,从而向数据所在的region的regionserver发起数据读取请求。
  6. 数据首先先会从regionserver中的blockcache中查找,如果数据恰好在blockcache中有完整数据则直接将数据读取,如果数据缺省,则会放弃带blockcache中读取。
  7. 在blockcache读取不成功后,会在对应memstore中进行数据读取,基本流程和在blockcache中读取类似,有完整则读取,否则放弃。
  8. 在两个缓存中都没有完整数据则会进入到storefile中进行查找数据。
    • 由于在blockcache和memstore都是处于内存之中,读取数据的速度较快,而在storefile中读取较慢,而storefile又是由memstore在满足衣服一定条件下fulsh生成,多次flush就会产生多个storefile文件,那么如何快速确定数据在那么storefile中就非常重要。
      1. 通过布隆过滤器确定数据大概在那些storefile上,确定搜索范围
        • 布隆过滤器的特点是:
          1. 如果判断存在,则不一定存在
          2. 如果判断不存在,则一定不存在
      2. 根据布隆过滤器筛选的结果,在从Hfile(storefile在hdfs上实际存储的形式)的数据索引信息确定数据是否真实存在该storefile,如果真实存在,则将数据取出
  9. 将数据返回给客户端(client)

Memstore flush

当Memstore满了或者达到一定条件后需要进行落盘处理(写如HDFS文件系统中)

触发条件

  1. 当一块Memstore的大小达到块的大小(128M)就会出发flush机制,将整块region的memstore都flush。
  2. 当region中所有的memstore的总大小达到512M时,该region中的所有memstore都会flush
  3. 当regionserver中所有的region的所有的memstore的总大小达到java_heapsize$\ast $40%$\ast $0.95的时候,会按照其所有MemStore的大小顺序(由大到小)依次进行刷写region。
  4. 当处于读写高峰的时候,第三个触发条件可以适当延迟,等到当regionserver中所有的region的所有的memstore的总大小达到java_heapsize$\ast $40%的时候,阻塞客户端写入,先进行flush。将regionserver中的所有额region按照memstore占用的空间大小顺序,优先flush占用空间多的region。等到flush到regionserver中所有的region的所有的memstore的总大小达到java_heapsize$\ast $40%*0.95的时候,停止flush,允许flush客户端写入
  5. 当region距离上一次flush超过1小时,该region所有memstore都会flush
  6. 手动flush:fllush ‘命名空间:表名’
  7. 如果region server中的预写文件数达到32的时候,也会触发flush。

注意:memstore在flush时,flush的单位时region,即flush就整个region都flush,因此当列族较多时,可能会产生很多小文件,因此实际工作场景中列族的个数一般设置为1个。

StoreFile Compaction

由于memstore每次flush都会产生一个新的storefile文件,等到storefile数量到达一定程度时,此时读取效率就会变得非常低下。同时当删除和覆盖数据时,其记录(由时间戳确定其记录的版本,在版本数量较小时,在添加新版本时,多余的旧的数据不会立马删除,而是会留存一定时间)也会保存一定时间,而这些数据又容易保存在不同的storefile中,空占存储空间。因此在查询时需要遍历所有的HFile,效率非常低下。

因此为了减少HFIle文件数量,可以对HFile文件进行合并,同时清理过期(被删除或者不需要的版本数据)数据,会进行storefile Compaction。

Compaction分为两种,分别是Minor Compaction和Major Compaction。

  1. Minor Compaction
    • 合并结果:会将临近的若干个较小的HFile合并成一个较大的HFile最终是多个小文件合并成为一个大文件
    • 合并过程:单纯的合并所有storefile文件,但不会清理过期和删除(被前面操作覆盖或者手动删除的)的数据
    • 触发条件:
      1. 小文件【小于128M】数量到达3个,直接合并
      2. 文件大于128M,且经过判断筛选出的文件数量达到3个,同样进行合并
        • 小文件判断式:当前文件大小 <=sum(比当前文件小的所有文件大小)*hbase.hstore.compaction.retio
  2. Major Compaction
    • 合并结果:会将一个Store下的所有的HFile合并成一个大HFile
    • 合并过程:并且清理掉过期和删除的数据
    • 触发条件:七天一次【一般禁用,改为手动触发】
      HBASE学习

注意:

  1. 此处合并和读取中的布隆过滤器并不冲突,合并其实在一定程度上提高了布隆过滤器的效率。
  2. 在storefile文件非常多时,经过滤后还是有可能留存大量文件,这对读取数据来讲非常不友好,因此合并文件后会提高布隆过滤器的效率。

Region Split

每个table最初只有一个region,随着数据不断的写入,region的读写压力会变得非常大,因此region会在合适的情况下进行split。

region的时机(HBASE版本不同,切分策略不同):

  1. HBASE_0.94之前:使用的是ConstantSizeRegionSplitPolicy策略

    简单描述就是当region中的store的大小超过一个阈值时进行切分。默认为10G

  2. 0.94版本-2.0版本:使用的是IncreasingToUpperBoundRegionSplitPolicy

    简单描述就是tableRegionCount==0 | | tableRegionCount>100 ? 10G : Math.min(10G,2$\ast $128M$\ast $tableRegionCount^3)

  3. 2.0版本: 使用的是SteppingSplitPolicy

    简单描述就是当前RegionServer中属于该Table的Region个数是否为1,是则他的分裂点为256M,否则就为10G(即当前region中属于该table的数量>=2,可以较有效的分担读写压力,暂时不用分)

    tableRegionCount == 1 ? 2 * 128M : 10G

HBASE学习

HBASE 优化

预分区

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

RowKey设计

Rowkey设计原则:

  1. 长度原则: rowkey的长度不能太长,一般保持在16字节以下
  2. 唯一性原则: 数据写入的时候两条数据的rowkey不能相同
  3. Hash原则: 保证数据分散存储
  • 热点问题解决方案:
    • 一条数据的唯一标识就是RowKey,那么这条数据存储于哪个分区,取决于RowKey处于哪个一个预分区的区间内,设计RowKey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。
      1. 生成随机数、hash、散列值
      2. 字符串反转
      3. 字符串拼接

内存优化

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

基础优化

  1. 允许在HDFS的文件中追加内容

    hdfs-site.xml、hbase-site.xml

    属性:dfs.support.append

    解释:开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true。

  2. 优化DataNode允许的最大文件打开数

    hdfs-site.xml

    属性:dfs.datanode.max.transfer.threads

    解释:HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为4096或者更高。默认值:4096

  3. 优化延迟高的数据操作的等待时间

    hdfs-site.xml

    属性:dfs.image.transfer.timeout

    解释:如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。

  4. 优化数据的写入效率

    mapred-site.xml

    属性:mapreduce.map.output.compress , mapreduce.map.output.compress.codec

    解释:开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。

  5. 设置RPC监听数量

    hbase-site.xml

    属性:hbase.regionserver.handler.count

    解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

  6. 优化HStore文件大小

    hbase-site.xml

    属性:hbase.hregion.max.filesize

    解释:默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

  7. 优化HBase客户端缓存

    hbase-site.xml

    属性:hbase.client.write.buffer

    解释:用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

  8. 指定scan.next扫描HBase所获取的行数

    hbase-site.xml

    属性:hbase.client.scanner.caching

    解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

  9. flush、compact、split机制

    当MemStore达到阈值,将Memstore中的数据Flush进Storefile;compact机制则是把flush出来的小文件合并成大的Storefile文件。split则是当Region达到阈值,会把过大的Region一分为二。涉及属性:

    hbase.hregion.memstore.flush.size:134217728

    hbase.regionserver.global.memstore.size.lower.limit 0.95

    hbase.regionserver.global.memstore.size 0.4

上一篇:自动完成问卷调查


下一篇:《C++ Primer》第12章 12.3节习题答案