【原理】数据模型&系统架构

2021-12-06 10:47:19 浏览数 (1)

数据模型&系统架构

数据模型

HBase表结构

HBase表,本质是以Key-Value的方式存储,然后使用二维表的形式进行组织。每张表都属于一个NameSpace(命名空间)之下,它是对表的逻辑分组,类似于关系数据库中的Database;利用命名空间,在多租户场景下可做到更好的资源和数据隔离。

HBase表和普通的二维表一样,有多行,每行有多个字段。其中RowKey字段是固定的,它是HBase表的唯一主键,用来唯一标识表中的某一条数据,它按照字典序排列,大小为64K,这里有rk001、rk002两条数据。

每一条数据中,包含字段name、age、telephone、course、score,但与关系型数据库中的二维表不同的是,name、age、telephone被放置在BasicInfo下,而course、score被放置在CourseInfo下,那其实BasicInfo、CourseInfo是列族,用来对列进行组织。

从命名上也可以看出端倪,name、age、telephone属于基本信息,被组织到了BasicInfo列族中;而course、score属于课程信息,被归纳到CourseInfo列族中。HBase的列式存储,其实是基于列族的,每个列族下的数据在物理位置上存放在一起,权限控制、存储以及调优都在列族层面进行,而不是对每一列数据进行单独放置。

每个列族下的字段,称为列限定符,如表中的name、age、telephone;这样的话,HBase某一列的列名就由列族和列限定符共同组成,它们之间使用冒号隔开,如BasicInfo:name、BasicInfo:age。

这是在纵向上,HBase表与普通二维表的不同;但从横向上来看,也有些奇怪,因为通过rowkey主键定位到的某一条数据,比如rk001,在图中好像是由多行组成的。

这里其实就印证了之前讲过的,HBase本质上是一个Key-Value数据库,在往某一行进行数据插入时,并不能像SQL一样,直接对多个字段进行插入,比如insert into … values(‘zhangsan’,18,‘1590939995’,‘math’,90);而是每次只能单独对某一个Value值进行单独的插入,比如对于name ‘zhangsan’,首先需要从横向上使用rowkey定位行:rowkey=rk001,再从纵向维度上使用列族、列限定符来定位列:BasicInfo:name,此时,key是通过rowkey、列族、列限定符来确定的,然后对value值’zhangsan’进行插入。

所以对某一行数据的插入,需要执行多次,每次只插入一个value值,这样,在图中体现出来的就像是多行,其实一个rowkey只对应一行数据,只是插入方式与普通二维表有区别。

但在BasicInfo:telephone这列中,就又有歧义了,它存在两个值,1590939995、1380100001。这是怎么回事?其实HBase底层的数据存放在HDFS中,但HDFS本身不支持数据修改,只支持追加和删除,那这样的话,HBase的数据需要进行修改时,应该怎样解决?HBase给出的办法是时间戳,每条数据在插入时,都会带一个时间戳,使用当前的时间来标记版本;如果数据发生修改,则不需要管之前的历史记录,而直接将修改的数据进行追加,因为新追加的数据时间戳是最新的,所以在读取时只需要读最新时间戳(版本)的数据即可,这样的话,其实就是将随机的修改转化成了追加的操作。

所以BasicInfo:telephone中的1590939995、1380100001两个值,1380100001时间戳版本为t9,是最新修改后的数据。

时间戳的类型是 64位整型,它可以在数据写入时由系统自动赋值(精确到毫秒的当前系统时间),也可以由客户显式赋值,为了避免版本冲突,必须生成具有唯一性的时间戳。

当然,因为HBase保存了数据的多个版本,所以在读取时,也可以指定数据的历史版本;如指定rowkey=rk001,BasicInfo:telephone中时间戳为t5的数据,则会将1590939995提取出来。但这样的话,随着修改次数的不断增加,数据冗余就会越来越严重,此时HBase会定期对数据进行合并,对历史版本的数据进行删除。

图中是将时间戳作为单独的一列,其实是为了形象的表示HBase的表结构,在实际情况中,时间戳是与数据存放在一起的,每个数据在插入时都会自带时间戳标识。

这样的话,HBase表结构基本上就清楚了。所以,有时候会称HBase表是一张四维表;比如定位到value数据’zhangsan’,需要rowkey=rk001,列族=BasicInfo,列限定符=name,时间戳=t1,这4个维度来共同完成。默认情况下,不需要指定时间戳,HBase会默认返回最新时间戳版本的数据。当然,称HBase表为三维表也没有问题,此时使用rowkey、列名(列族:列限定符)、时间戳,来定位某一个value数据,是将列族与列限定符共同作为一个维度。

通过4个维度,定位到的某个value的位置(表中的某一格),被称为Cell(单元格),用于存放单个value数据,并携带数据的时间戳版本。它是HBase表中最细粒度的单位。

而且,在HBase中,并没有数据类型这一说,它存放的所有数据均为字节数组byte[];当然也可以说Cell(单元格)中存放的数据类型为字节数组。

HBase表特点

Hbase表有以下几个特点:

  1. 数据规模大:HBase作为大数据的分布式NoSQL数据库,单表可容纳数十亿行,上百万列;数十亿行倒是不奇怪,上百万列的扩展性就足以表示它列式存储的特性了。
  2. 面向列族:Hbase的列式存储是面向列族的,对列族进行单独的存储和权限控制,并且支持列族独立查询。
  3. 稀疏:正是因为列式存储,带来了它稀疏的特性,不用像行式存储一样,为了快速定位到某一行的数据,需要每一行的数据大小是固定的,即使数据为空,也需要使用占位符代替。而列式存储,则针对列进行数据存放并建立索引,所以如果某个值为空,则在底层存储时就不占用空间,减少了空间的浪费,所以称HBase表为稀疏表。
  4. 无模式:HBase表的每行可以有任意多的列,列可以动态增加。而且对于列的类型没有限制。
  5. 数据无类型:HBase表中的所有数据都以字节数组形式存储,这也是它可以方便的存储半结构化、非结构化数据的原因。
  6. 数据多版本:单元格的值可以有多个版本,利用时间戳来标识版本。但一定要注意的是,时间戳的单位是毫秒,所以在1毫秒内,对数据进行了多次插入、修改,便会出现类似关系型数据库中的主键冲突的情况。如果在企业中,比如流处理场景中,发生了这种情况,则需要在操作HBase前,将对同一个Rowkey进行操作的命令提前合并,保证数据一致性。

系统架构

架构图

HBase是经典的Hadoop架构,即主从模式。主节点为HMaster,从节点为HRegionServer。其中从节点HRegionServer负责HBase数据的存储;而主节点HMaster则存储数据的元数据信息,即数据的寻址入口,并且管理整个集群,如HRegionServer的运行状态、负载均衡、容灾处理等。

一般情况下,因为主节点HMaster存储了数据的元数据信息,那么客户端Client对于数据的处理请求,便会提交到主节点中获取数据的存储位置。但在HBase中,Client与HMaster并没有直接进行交互,而是HMaster将元数据存放到了Zookeeper中,Client则直接从Zookeeper中获取元数据,从而获得数据的存放位置,这样能够减轻HMaster的压力。

HBase表数据,最终会存储到各个从节点HRegionServer中;假设一张HBase表有1000行数据,首先它会按照行进行切分,现拆分为2份,每份500行数据,分别被调度到两个HRegionServer中,被存储为HRegion。换句话说,HRegion里存放的是一张HBase表的一部分数据。

那既然HBase是列式存储的数据库,那每个HRegion中保存的500行数据,就要按照列族进行拆分存储;所以在HRegion中,每个列族会被存储为一个Store。对应的数据进入到Store中时,不会直接落盘,为了保证性能,Store中有MemStore内存缓存区用于数据缓存;当MemStore中的数据达到阈值时,会将数据刷写到磁盘中生成StoreFile。StoreFile最终会被存储到HDFS中,在HDFS中它又被称为HFile,其实StoreFile和HFile的内容相同,只不过在不同存储位置的命名不同。

但这里,就有一个问题出现了,既然MemStore是一个内存缓存区,那么如果数据刚进入到MemStore中,还没有落盘,当前的从节点HRegionServer便宕机了,此时数据肯定就丢失了。为了避免这种情况发生,和传统数据库一样,HBase有WAL预写机制来保证数据的安全性,每个HRegionServer都有一个HLOG文件,在数据写入MemStore之前,会先保存到HLOG中,避免数据数据丢失。而HLOG会存储在HDFS中,这样的话,如果MemStore数据丢失,则还可以从HLOG中对数据进行恢复。但HBase数据恢复过程较慢,这也是被很多开发者所诟病的地方。

组件功能

HBase的基本架构掌握后,再来系统的整理一下它各个组件所负责的功能。

HMaster(Master)

HMaster是HBase的主节点,负责集群和元数据的管理,它的主要功能有:

  1. 负责HRegionServer的负载均衡
  2. 为HRegionServer分配Region,如果HRegionServer宕机后,会重新分配其上的Region
  3. 不处理Client的数据读写请求
  4. 管理元数据(数据的寻址入口)
  5. 管理表的创建、删除和修改

其实,归纳起来,首先是负责集群的管理,主要是HRegionServer的负载均衡,保证每个HRegionServer上的数据量基本是差不多的,不会出现数据倾斜的情况;并进行负责容灾处理,如果某个HRegionServer节点宕机之后,能够将其上面的Region进行重分配。

其次,负责元数据的管理,因为HMaster并不接收Client的数据读写请求,为了减轻HMaster的压力和加快并发性能,会将元数据(数据寻址入口)存放到Zookeeper中,并定期对元数据进行维护和管理,而Zookeeper是一个负责分布式协调的大数据产品,性能更为出色,客户端在读写数据时,直接从Zookeeper中获取元数据;既然负责元数据的管理,那么对于表的创建、删除和修改,这些涉及到元数据的DDL操作,都会由HMaster来处理,并进行元数据的同步。

HRegionServer(Slave)

HRegionServer是HBase的从节点,它的主要功能有:

  1. 负责Region的存储
  2. 管理Region Split(分裂)
  3. 管理StoreFile Compaction(合并)
  4. 处理Client的数据读写请求

所以,HRegion主要负责数据存储,将Region存储后,负责管理Region的分裂、合并(后面会讲到);然后处理客户端对数据的写入、读取的操作。

Zookeeper

Zookeeper负责集群的分布式协调,它在大数据集群中非常重要,除了可以协助多个主节点实现高可用(进行主备切换),监控集群各个节点状态之外,还可以进行一些重要数据的存储,如元数据、配置文件等。

在HBase集群中,它的作用有:

  1. 实现HMaster高可用
  2. 监控HRegionServer的上下线信息,并通知HMaster
  3. 存储元数据的寻址入口
  4. 存储所有Region的寻址入口

Zookeeper在这里的功能首先是协助HBase进行集群管理,帮助HMaster实现高可用,也辅助完成从节点的状态收集,并通知主节点;其次,它辅助完成客户端对数据的寻址,存储了元数据的寻址入口,并且存放了所有Region的寻址入口。

在HBase中,每条数据存放在哪个HRegionServer节点上,会记录在.META表中,.META表就是一张普通HBase表,只是它用于存放了数据的寻址信息,即元数据信息;既然是普通表,那便会存放在对应的HRegionServer中,Zookeeper保存的其实是.META表的寻址入口,让客户端去对应的HRegionServer中读取.META表,获取元数据信息。

Client

客户端Client是访问HBase的接口,为了加快数据访问速度,会将元数据、Region位置等信息缓存在Client Cache中。并且会定期重新向Zookeeper获取.META表的入口信息,从对应的HRegionServer上拉取对.META表后,更新Client Cache中的元数据。

Region

Region是分布式存储和负载的最小单元。系统将表水平划分(按行)为多个Region,每个Region保存表的一段连续数据。

默认每张表开始只有一个Region,随着数据不断写入,Region不断增大,当Region大小超过阀值时,当前Region会分裂成两个子Region。随着Region的不断增多,HMaster会将部分Region迁移到其他HRegionServer中,实现负载均衡。

HBase表通常被保存在多个HRegionServer的多个Region中。

Store

一个Region由多个Store组成,每个Store存储一个列族。Store由内存中的MemStore和磁盘中的若干StoreFile组成。

MemStore与StoreFile

MemStore是Store的内存缓冲区,数据读写都先访问MemStore。StoreFile是MemStore的磁盘溢写文件,在HDFS中被称为HFile。

写数据时,先写MemStore,当数据量超过阈值时,HRegionServer会将MemStore中的数据溢写磁盘,每次溢写都生成一个独立的StoreFile(HFile)。那意味着MemStore中存储的永远是最新写入的,且还没有溢写到磁盘的数据,所以Client读取数据时,先找MemStore,再找StoreFile。

当Store中的StoreFile数量超过阈值时,HRegionServer会将若干小StoreFile合并为一个大StoreFile;当Region中最大Store的大小超过阈值时,HRegionServer会将其等分为两个子Region。

HLOG

HLOG是以WAL(Write Ahead Log,预写日志)方式写数据时产生的日志文件,它保证HRegionServe在意外宕机时可以进行数据恢复。

每个HRegionServe都会有一个HLOG,为了避免写入MemStore内存缓存区中的数据丢失,数据会先写入到HLog中,然后再写入MemStore,最后才会溢写成为StoreFile。HBase会将已经保存到HDFS中的StoreFile数据,定期在HLOG中进行清除,避免HLOG文件过大。

那正是因为一个HRegionServe只有一个HLOG,而HRegionServe中有多个Region,每个Region又会包含多个Store,所以记录的数据会混在一起。于是在HRegionServe后,使用HLOG进行数据恢复的过程,便会很慢;因为HMaster首先要处理HLog,针对不同的Region拆分HLog,然后将当前宕机节点的Region分配到其它HRegionServe节点后,通过HLog将尚未持久化的数据重新写入MemStore,然后溢写到StoreFile。

0 人点赞