3-HBase体系结构

结构体系

部署架构

一个HBase集群由一个Master(也可以把两个Master做成 High Available)和多个RegionServer组成。

HBase有两种服务器:Master服务器和RegionServer服务器。

  • Master服务器负责维护表结构信息

  • RegionServer服务器负责存储实际的数据,他们直接存储在Hadoop的HDFS上

    • RegionServer非常依赖ZooKeeper服务
    • ZooKeeper管理了HBase所有RegionServer的信息,包括具体的数据段存放在哪个RegionServer上。

image-20200908100322777

体系架构

img

HBase中的组件包括Client、Zookeeper、HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog等

Client

当客户端从ZooKeeper获取RegionServer的地址后,它会直接从RegionServer获取或操作(插入、删除)数据,而不经过Master。

Client 访问用户数据前需要首先访问 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问。

  • .META.:记录了用户所有表拆分出来的的 Region 映射信息,.META.可以有多个 Regoin

  • -ROOT-:记录了.META.表的 Region 信息,-ROOT-只有一个 Region,无论如何不会分裂

寻址方式
三层查询(HBase-0.96 版本以前)

image-20200908172700454

  1. 用户通过查找zk(ZooKeeper) 的/hbase/root-regionserver节点来知道-ROOT-表在什么RegionServer上
  2. Client 请求-ROOT-所在的 RegionServer 地址,获取.META.表的地址,Client 会将-ROOT-的相关信息 cache 下来,以便下一次快速访问
  3. Client 请求.META.表的 RegionServer 地址,获取访问数据所在 RegionServer 的地址, Client 会将.META.的相关信息 cache 下来,以便下一次快速访问
  4. Client 请求访问数据所在 RegionServer 的地址,获取对应的数据

总结:用户需要 3 次请求才能直到用户 Table 真正的位置,这在一定程序带来了性能的下降。

二层查询(HBase-0.96 版本以后)

使用 3 层设计的主要原因是考虑到元数据可能需要很大。

每行 METADATA 数据存储大小为 1KB 左右,如果按照一个 Region 为 128M 的计算,3 层设计可以支持的 Region 个数为 2^34 个,采用 2 层设计可以支持 2^17(131072)。使用 2 层设计的情况下,一个集群可以存储 4P 的数据。这仅仅是一个 Region 只有 128M 的情况下。 2 层设计就可以满足集群的需求,因此在 0.96 版本以后就去掉 了-ROOT-表了。

image-20200908172502071

  1. 客户端先通过ZooKeeper的/hbase/meta-region-server节点查询到哪台RegionServer上有hbase:meta表。
  2. 客户端连接含有hbase:meta表的RegionServer。 hbase:meta表存储了所有Region的行键范围信息, 通过这个表就可以查询出你要存取的rowkey属于哪个Region的范围里面, 以及这个Region又是属于哪个RegionServer。
  3. 获取这些信息后, 客户端就可以直连其中一台拥有你要存取的rowkey的RegionServer, 并直接对其操作。
  4. 客户端会把meta信息缓存起来,下次操作就不需要进行以上加载hbase:meta的步骤了。

Zookeeper

元数据表hbase:meata的位置存储在ZooKeeper

HDFS

真正承载数据的载体

Master

Master只负责各种协调工作,如建表、删表、移动Region、合并等操作。

RegionServer

RegionServer就是存放Region的容器,直观上说就是服务器上的一个服务。RegionServer上有一个或者多个Region,数据就存储在Region上。

RegionServer的内部架构图

image-20200908144833952

  • WAL(Write-Ahead Log):预写日志。当操作到达Region的时候,HBase先把操作写到WAL里面。 HBase会先把数据放到基于内存实现的Memstore里,等数据达到一定的数量时才刷写(flush)到最终存储的HFile内。

  • 多个Region:Region相当于一个数据分片,每一个Region都有起始rowkey和结束rowkey,代表了它所存储的row范围。

Region

Region就是一段数据的集合。HBase中的表一般拥有一个到多个Region。
Region有以下特性:

  • Region不能跨服务器,一个RegionServer上有一个或者多个Region。
  • 数据量小的时候,一个Region足以存储所有数据;但是,当数据量大的时候,HBase会拆分Region。
  • 当HBase在进行负载均衡的时候,也有可能会从一台RegionServer上把Region移动到另一台RegionServer上。
  • Region是基于HDFS的,它的所有数据存取操作都是调用了HDFS的客户端接口来实现的。

一个Region就是多个行的集合。在Region中行的排序按照行键(rowkey)字典排序。

Region 内部结构图

image-20200908145939866

一个Region包含有:

  • 多个Store:每一个Region内都包含有多个Store实例。一个Store对应一个列族的数据,如果一个表有两个列族,那么在一个Region里面就有两个Store。在最右边的单个Store的解剖图上,我们可以看到Store内部有MemStore和HFile这两个组成部分。

Store

Store中有两个重要组成部分:

  • MemStore:每个Store中有一个MemStore实例。 数据写入WAL之后就会被放入MemStore。 MemStore是内存的存储对象, 只有当MemStore满了的时候才会将数据刷写(flush) 到HFile中

  • HFile:在Store中有多个HFile。 当MemStore满了之后HBase就会在HDFS上生成一个新的HFile, 然后把MemStore中的内容写到这个HFile中。HFile直接跟HDFS打交道,它是数据的存储实体。

Store内部结构图

image-20200908155023755

MemStore

Memstore是存储在内存中,Memstore存在的意义是维持数据按照rowkey顺序排列,而不是做一个缓存

使用内存先把数据整理成顺序存放,然后再一起写入硬盘。

数据被写入WAL之后就会被加载到MemStore中去。 MemStore的大小增加到超过一定阀值的时候就会被刷写到HDFS上, 以HFile的形式被持久化起来。

HFile(StoreFile)

HFile是数据存储的实际载体,我们创建的所有表、列等数据都存储在HFile里面。HFile是由一个一个的块组成的。 在HBase中一个块的大小默认为64KB, 由列族上的BLOCKSIZE属性定义。

MemStore刷写而成的文件叫HFile, StoreFile就是HFile的抽象类

HFile的组成

image-20200908160157055

  • Data (数据块) :每个HFile有多个Data块。存储HBase表中的数据。可选的
  • Meta(元数据块):Meta块是可选的,Meta块只有在文件关闭的时候才会写入。Meta块存储了该HFile文件的元数据信息
  • FileInfo(文件信息):只有在文件关闭的时候写入。存储的是这个文件的信息,比如最后一个Key(Last
    Key) ,平均的Key长度(Avg Key Len)等。必选的
  • DataIndex(存储Data块索引信息的块文件):索引的信息也就是Data块的偏移值(offset)。可选的
  • MetaIndex(存储Meta块索引信息的块文件):可选的
  • Trailer:存储了FileInfo、 DataIndex、 MetaIndex块的偏移值。必选的
Data数据块

Data数据块的第一位存储的是块的类型, 后面存储的是多个KeyValue键值对, 也就是单元格(Cell)的实现类。 Cell是一个接口,KeyValue是它的实现类。

image-20200908162702715

  • BlockType(块类型)
    • DATA
    • ENCODED_DATA
    • LEAF_INDEX
    • BLOOM_CHUNK
    • META
    • INTERMEDIATE_INDEX
    • ROOT_INDEX
    • FILE_INFO
    • GENERAL_BLOOM_META
    • DELETE_FAMILY_BLOOM_META
    • TRAILER
    • INDEX_V1
KeyValue类

一个KeyValue类里面最后一个部分是存储数据的Value,而前面的部分都是存储跟该单元格相关的元数据信息。如果你存储的value很小,那么这个单元格的绝大部分空间就都是rowkey、columnfamily、column等的元数据,所以大家的列族和列的名字如果很长,大部分的空间就都被拿来存储这些数据了。

采用适当的压缩算法就可以极大地节省存储列族、 列等信息的空间。压缩和解压必然带来性能损耗

KeyValue类结构图

image-20200908163623003

数据存储顺序

WAL是存储在HDFS上的, Memstore是存储在内存中的, HFile也是存储在HDFS上的。

数据是先写入WAL, 再被放入Memstore, 最后被持久化到HFile中。

预写日志(Log)

预写日志(Write-ahead log,WAL) 就是设计来解决宕机之后的操作恢复问题的。数据到达Region的时候是先写入WAL,然后再被加载到Memstore的。WAL的数据是存储在HDFS。

关闭或打开WAL特性

WAL是默认开启的

Mutation.setDurability(Durability.SKIP_WAL)

-- 方法来设置和获取字段的值
Mutation.getDurability()
  • 在HBase的Java API中,指定写入时不使用WAL log
Put put = new Put(rowKey);
put.setWriteToWAL(false);
  • 在HBase shell中,关闭一张表的WAL log
disable 'TABLE_NAME'
alter 'TABLE_NAME', DURABILITY => 'SKIP_WAL'
enable 'TABLE_NAME'
延迟(异步)同步写入WAL
Mutation.setDurability(Durability.ASYNC_WAL)

DURABILITY可选的值有ASYNC_WAL, FSYNC_WAL, SKIP_WAL, SYNC_WAL(默认值), USE_DEFAULT等

  • ASYNC_WAL
    Write the Mutation to the WAL asynchronously
  • FSYNC_WAL
    Write the Mutation to the WAL synchronously and force the entries to disk.
  • SKIP_WAL
    Do not write the Mutation to the WAL
  • SYNC_WAL
    Write the Mutation to the WAL synchronously.
  • USE_DEFAULT
    If this is for tables durability, use HBase's global default value (SYNC_WAL).
WAL 滚动

WAL的检查间隔由hbase.regionserver.logroll.period定义, 默认值为1小时。检查的内容是把当前WAL中的操作跟实际持久化到HDFS上的操作比较,看哪些操作已经被持久化了,被持久化的操作就会被移动到.oldlogs文件夹内

一个WAL实例包含有多个WAL文件。 WAL文件的最大数量通过hbase.regionserver.maxlogs(默认是32) 参数来定义

触发滚动条件
  • 当WAL文件所在的块(Block) 快要满了
  • 当WAL所占的空间大于或者等于某个阀值,该阀值的计算公式:hbase.regionserver.hlog.blocksize * hbase.regionserver.logroll.multiplier
    • hbase.regionserver.hlog.blocksize: 存储系统的块大小,若基于HDFS,则设定为HDFS的块大小
    • hbase.regionserver.logroll.multiplier:默认值0.95。即当WAL文件所占的空间大于或者等于95%的块大小, 则这个WAL文件就会被归档到.oldlogs文件夹内
WAL归档

WAL文件被创建出来后会放在/hbase/.log,一旦WAL文件被判定为要归档,则会被移动到/hbase/.oldlogs文件夹。

当这个WAL不需要作为用来恢复数据的备份时,Master会负责定期地去清理.oldlogs文件夹。

引用WAL文件的场景:

  • TTL进程: 该进程会保证WAL文件一直存活直到达到hbase.master.logcleaner.ttl定义的超时时间(默认10分钟) 为止
  • 备份(replication) 机制: 如果你开启了HBase的备份机制,那么HBase要保证备份集群已经完全不需要这个WAL文件了,才会删除这个WAL文件。

只有当该WAL文件没有被以上两种情况引用时, 才会被系统彻底地删除掉。

数据存储架构

结构图
表结构图

image-20200908110426451

行结构

image-20200908102750484

Namespace(表命名空间)

表命名空间的作用是把多个属于相同业务领域的表分成一个组。

在建表时可以添加上命名空间( :

)

保留表空间

HBase中预定义2个保留表空间

  • HBase: 系统表空间,用于HBase内部表
  • default: 那些没有定义表空间的表都被自动分配到这个表空间下
Table(表)

一个表由一个或者多个列族组成

Row(行)

一个行包含了多个列,这些列通过列族来分类。一行中的数据可以分布在不同的服务器上。

Row key

rowkey行键可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),最好是16。在 HBase 内部,rowkey 保存为字节数组。每个行(row)都拥有唯一的行键(row key)来确定其唯一性。rowkey就是决定row存储顺序和位置的唯一凭证。

HBase中无法根据某个column来排序,只能根据rowkey来排序(字典顺序)

column

最基本的存储单位是列(column),一个列或者多个列形成一行(row)。

在HBase中,行跟行的列可以完全不一样,这个行的数据跟另外一个行的数据也可以存储在不同的机器上,甚至同一行内的列也可以存储在完全不同的机器上。

Hbase只支持3中查询方式

1、基于Rowkey的单行查询

2、基于Rowkey的范围扫描

3、全表扫描

Column Family

若干列可以组成列族(Column Family)。Hbase通过列族划分数据的存储,列族下面可以包含任意多的列,实现灵活的数据存取。

Hbase表的创建的时候就必须指定列族,不需要指定列。

Hbase的列族不是越多越好,官方推荐的是列族最好小于或者等于3。我们使用的场景一般是1个列族。

表属性(如:过期时间,数据块缓存,是否压缩等属性)都是定义在列簇上。

在HBase中一个列的名称前面总是带着他所属的列族,它的格式是( 列族:列名 )。

TimeStamp(时间戳/版本号)

在Hbase中使用不同的timestame来标识相同rowkey行对应的不同版本的数据。用来标定同一个列中多个单元格的版本号。

版本通过时间戳来索引。时间戳的类型是 64 位整型。时间戳可以由hbase(在数据写入时自动)赋值,它是精确到毫秒的当前系统时间。时间戳也可以由用户显式赋值。每个 cell 中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

多版本数据管理

hbase 提供了两种数据版本回收方式

  • 保存数据的最后 N个版本
  • 保存最近一段时间内的版本(设置数据的生命周期 TTL)
Cell(单元格)

一个列上可以存储多个版本的值,每个版本就称为单元格(Cell)。多个版本的值被存储到多个单元格中,多个版本之间用timestame(Version)来区分。因此,由行键:列族:列:版本号(rowkey:column family:column:version)来唯一确定一条结果。

posted @ 2020-09-09 10:11  KuBee  阅读(508)  评论(0编辑  收藏  举报