大数据技术原理与应用 - (4). 分布式数据库 HBase

大数据技术原理与应用 - (4). 分布式数据库 HBase

【第二篇】 - 大数据存储与管理, 《大数据技术原理与应用, 林子雨》

本篇介绍大数据存储与管理相关技术的概念与原理,包括

HBase 是针对 Google BigTable 的开源实现,是一个高可靠、高性能、面向列、可伸缩的分布式数据块,主要用来存储非结构化和半结构化的松散数据。

本章介绍 HBase 与关系型数据库的区别、访问接口、数据模型、实现原理和运行机制。

HBase 简介

HBase 是针对 Google BigTable 的开源实现,是一个高可靠、高性能、面向列、可伸缩的分布式数据块,主要用来存储非结构化和半结构化的松散数据。


Hadoop 生态系统中 HBase 与其他部分的关系

HBase 与传统数据库的区别

传统关系数据库
HBase
数据类型 关系模型,具有丰富的数据类型和存储方式。 采用了更加简单的数据模型,它把数据存储为未经解释的字符串
数据操作 包含了丰富的操作,如增删改查等,还会涉及复杂的多表连接。 不存在表与表的关系,只有简单的插入、查询、删除、清空等操作。
存储模式 基于行模式存储,元组或行会被连续地存储在磁盘页中。在读取数据时,需要顺序扫描每个元组。 基于列存储的,每个列族都由几个文件保存,不同列族的文件是分离的。
数据索引 通常可以针对不同列构建复杂的多个索引 (主索引 + 多个二级索引),以提高数据访问性能。 只有一个索引——行键。
数据维护 更新操作会用最新的当前值去替换记录中原来的旧值,旧值被覆盖后就不会存在。 HBase中执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧有的版本仍然保留。
可伸缩性 很难实现横向扩展 (增加机器),纵向扩展 (升级内存、cpu 等) 的空间也比较有限。 为了实现灵活的水平扩展而开发的,能够轻易地通过在集群中增加或者减少硬件数量来实现性能的伸缩。

HBase 访问接口

类型
特点
场合
Native Java API 最常规和高效的访问方式 适合 Hadoop MapReduce 作业并行批处理 HBase 表数据
HBase Shell HBase 的命令行工具,最简单的接口 适合 HBase 管理使用
Thrift Gateway 利用 Thrift 序列化技术,支持 C++、PHP、Python 等多种语言 适合其他异构系统在线访问 HBase 表数据
REST Gateway 解除了语言限制 支持 REST 风格的 Http API 访问 HBase
Pig 使用 Pig Latin 流式编程语言来处理 HBase 中的数据 适合做数据统计
Hive 简单 当需要以类似 SQL 语言方式来访问 HBase 的时候

HBase 数据模型

  • HBase 是一个稀疏、多维度、排序的映射表,这张表的索引是行键 (Row Key)、列族 (Column Family)、列限定符 (Column Qualifier) 和时间戳 (Timestamp) 来进行索引
  • 每个值是一个未经解释的字符串,没有数据类型
  • 用户在表中存储数据,每一行都有一个可排序的行键和任意多的列
  • 表在水平方向由一个或者多个列族组成,一个列族中可以包含任意多个列,同一个列族里面的数据存储在一起
  • 列族支持动态扩展,可以很轻松地添加一个列族或列,无需预先定义列的数量以及类型,所有列均以字符串形式存储,用户需要自行进行数据类型转换
  • HBase中执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧有的版本仍然保留(这是和HDFS只允许追加不允许修改的特性相关的)

数据模型的相关概念

概念
描述
HBase 采用表来组织数据,表由行和列组成,列划分为若干了列族。
表由若干行组成,行由行键 (Row Key) 来标识。访问方式:1) 单个行键访问;2) 行键区间访问;3) 全表扫描
列族 1. 表被份组成许多列族的集合,它是基本访问控制单元。列族需要在创建时定义好,数量不能太多,不能频繁修改,存储在一个列族下的所有数据都属于同一数据类型。
2. 表中的列都归属于某个列族下,数据存放在列族的某个列下。
列限定符 列族中的数据通过列限定符 (或列) 来定位。不用事先定义,无需再不同行间保持一致,没有数据类型。
单元格 单元格 (cell) 存储的数据没有数据类型 (未经解释的字符串) ,格中可以保存一个数据的多个版本,每个版本对应一个不同的时间戳。
时间戳 每次对一个单元格执行操作 (新建、修改、删除) 时,HBase 都会隐式地自动生成并存储一个时间戳,用于定位格中不同版本地数据。

数据坐标

HBase 用四维坐标定位一个单元格: [行键, 列族, 列限定符, 时间戳]


HBase 数据模型的一个实例

如果把思维坐标当作整体,可以视为 “键”,单元格中的数据视为 “值” 的话,HBase可以看作一个键值数据库。

[“201505003”, “Info”, “email”, “1174184619081”] xie@qq.com
[“201505003”, “Info”, “email”, “1174184620720”] you@163.com

视图概念


HBase 数据的概念视图

HBase 表的概念试图中,每行都包含相同的列族,但是行不需要在每个列族里存储数据。从这个角度看,HBase 表是一个稀疏的映射关系,即里面存在很多空的单元格。

物理视图


HBase 数据的物理视图

物理存储层面,HBase 采用了基于列的存储方式,不像传统关系型数据库那样采用基于行存储的方式,这是 HBase 与传统数据库的重要区别。因此概念视图中的数据在物理层面实际上被存成了两个小片段,也就是 HBase 表按照 contentsanchor 两个列族分别存放,属于同一列族的数据保存在一起,同时每个列族一存放的还有行键和时间戳。

面向列的存储


行式数据库与列式数据库示意图

列式数据库采用 DSM (Decomposition Storage Model) 存储模型,DSM 会对关系进行垂直分解,并为每个属性分配一个子关系。因此,一个具有 $n$ 个属性的关系会被分解为 $n$ 个子关系,每个子关系单独存储,每个子关系只有当前相应的属性被请求时,才会被访问。
DSM 是以关系数据库中的属性或列为单位进行存储的,关系中多个元组的同一属性值会被存储在一起,而一个元组中的不同属性值通常会被存放在不同的磁盘页中。 HBase 是以列族为单位进行分解,而不是每个列都不单独存储。

  • 行存储:数据按行存储在底层文件系统中。通常,每一行会被分配固定的空间。

    • 优点:有利于增加、修改整行记录等操作;有理由数据的读取操作。
    • 缺点:单列查询时,会读取一些不必要的数据。
  • 列存储:数据以列为单位,存储在底层文件系统中。

    • 优点:有利于面向单列数据的读取、统计等操作。
    • 缺点:整行读取时,可能需要多次I/O操作。

适用场景

  • 行式数据库:适合小批量得数据处理,如联机事务型数据处理。主要用于如银行个人信息数据库之类得场景,对数据不出错要求较高。
  • 列式数据库:适合批量数据处理和即席查询 (Ad-Hoc Query)。主要用于数据挖掘、决策支持、地理信息系统等查询密集型系统中,因为每次查询都不必遍历所有数据库。

为什么列式存储适合数据分析

  • 因为分析中常常是以一个一个属性 (也就是列) 进行分析的,而列式数存储可以直接取出需要分析的那一列数据。相反地,行式数据库中如果需要取出某一列 (例如性别、年龄) 进行分析,需要扫描整个数据包才能取出对应数据。

HBase 存储原理

HBase 功能组件

HBase的实现包括三个主要的功能组件:

  1. 库函数:链接到每个客户端
  2. 一个 Master 服务器
    • 负责管理和维护 HBase 表的分区信息,如一个表被分成了哪些 Region 和被存放到哪台 Region 服务器。
    • 负责维护 Region 服务器列表,如监测 Region 服务器,确保它们之间负载均衡;对故障 Region 服务器中存储的 Region 进行重新分配。
    • 处理模式变化,如表和列族的创建。
  3. 多个 Region 服务器
    • 负责存储和维护分配给自己的 Region。
    • 处理来自客户端的读写请求。
  • 客户端并不依赖 Master,而是通过 Zookeeper 来获得 Region 位置信息,大多数客户端甚至从来不和 Master 通信,这种设计方式使得 Master 负载很小。

表和 Region

  • HBase 中存储了许多表。一个 HBase 表根据行键的字典序又被划分为许多 Region。
  • Region 是 HBase 分布式存储的最基本单元
  • 随着数据不断插入,Region 会持续增大,当 Region 中行数达到阈值 hbase.hregion.max.filesize,就会自动分裂成两个新的 Region。
    • 快速分裂,一般在2-3S内完成,因为只是修改只想信息,实际数据还是存在旧的 Region。
    • 直到”合并”过程把存储文件异步地写到独立的文件之后才会读取新文件。
  • 每个 Region 的最佳大小取决于单台服务器的有效处理能力。
    • 目前推荐 1~2GB 以上 (2013年后的硬件水平)
(左)一个 HBase 表被划分成多个 Region
(右)一个 Region 会分裂成多个新的 Region
  • 不同的 Region 可以分布在不同的 Region 服务器上
  • 同一个 Region 不会被分拆到多个 Region 服务器

不同的 Region 可以分布在不同的 Region 服务器上

Region 定位

HBase 表中有多个 Region,它们会被分发到不同的 Region 服务器上。因此,HBase 设计了三层结构实现 Region 的寻址和定位。


HBase 三层结构
  • Zookeeper: 文件记录了 -ROOT- 表 的位置信息。
  • -ROOT- 表: 记录. META. 表的 Region 的位置信息 (因为 .META. 表增大后会分裂成多个 Region)。
    • -ROOT- 表不能被分割,只有唯一一个 Region。
  • .META.表 (元数据表): 存储了 Region 和 Region 服务器的映射关系。
    • 当 HBase 表很大时, .META.表也会被分裂成多个 Region。

为了加快访问速度,.META. 表的全部 Region 都会被保存在内存中。

这样的设计能存多少数据?

假设 .META. 表中每行 (每个映射条目) 在内存中大约占 1 KB,每个 Region 限制为 128 MB。

  1. 一个 -ROOT- 表只有一个 Region, i.e., 128 MB 大小:
    • 128 MB 可以存 $128 MB/ 1KB = 2^{17}$ 行映射条目。
    • 也就是 一个 -ROOT- 表可以寻址 $2^{17}$ 个 .META. 表的 Region 位置信息。
  2. 同理,一个 .META. 表的 Region 可以寻址用户数据表的 Region 个数是 $128 MB/ 1KB = 2^{17}$。
  3. 最终三层结构可以保存的 Region 数目是 $(128 MB/ 1 KB) \times (128 MB/ 1 KB) = 2^{34}$ 个 Region。

客户端访问数据时的“三级寻址”:

  • 为了加速寻址,客户端会缓存位置信息,这样可以直接从客户端缓存中获取 Region 位置信息。
    • 解决缓存失效问题: 惰性监测。当访问数据时,发现缓存中 Region 位置信息不存在,才会判断出缓存失效。然后再重新启动上面的“三级寻址”过程重新获取最新的 Region 信息。
  • 寻址过程客户端只需要询问 Zookeeper 服务器,不需要连接 Master 服务器。

HBase 的运行机制

HBase 系统架构

HBase 系统架构包含下图组件。由于 HBase 通常采用 HDFS 作为底层数据存储,因此下图加入了 HDFS 和 Hadoop。


HBase 的系统架构
  1. 客户端 (Client)
    • 包含访问 HBase 的接口,同时在缓存中维护着已经访问过的 Region 位置信息,用来加快后续数据访问过程。
  2. Zookeeper
    • 实现集群的协同管理服务。Zookeeper 可以不是一台机器,可以是多台机器构成的集群。
    • Zookeeper 可以帮助选举出一个 Master 作为集群的总管,并保证在任何时刻总有唯一一个 Master 在运行,避免了 Master 的“单点失效”问题。
  3. Master: 主服务器Master主要负责表和Region的管理工作
    • 管理用户对表的增加、删除、修改、查询等操作。
    • 实现不同 Region 服务器之间的负载均衡。
    • 在 Region 分裂或合并后,负责重新调整 Region 的分布。
    • 对发生故障失效的 Region 服务器上的 Region 进行迁移。
  4. Region 服务器
    • 负责维护分配给自己的 Region,并响应用户的读写请求。

Region 服务器工作原理


Region 服务器向 HDFS 文件系统中读写数据

各个组件:

  • 每个 Region 服务器中的若干个 Region 公用一个 HLog
  • 每个 Region 中由多个 Store 组成
    • 每个 Store 对应表中一个列族的存储
    • 一个 Store 包含一个 MemStore 和若干个 StoreFile
  • MemStore 是在内存中缓存,保存最近更新的数据
  • StoreFile 是磁盘中的文件,这些文件都是 B树的结构,方便快速读取。
    • StoreFile 在底层的实现方式 HDFS 文件系统的 HFile

用户读写数据的过程

  • 当用户写入数据时,会被分配到相应Region服务器去执行。
    1. 用户数据首先被写入到 MemStoreHLog 中。
    2. 只有当操作写入 Hlog 之后,commit() 调用才会将其返回给客户端。
  • 当用户读取数据时,Region 服务器会首先访问 MemStore 缓存,如果找不到,再去磁盘上面的 StoreFile 中寻找。

缓存的刷新

  • MemStore 缓存容量有限,系统会周期性地调用 Region.flushcache()MemStore 缓存里地内容写到磁盘地 StoreFile 文件中,并清空缓存,同时在 HLog 文件中写入一个标记。
  • 每个 Region 服务器都有一个自己的 HLog 文件,每次启动都检查该文件,确认最近一次执行缓存刷新操作之后是否发生新的写入操作;如果发现更新,则先写入 MemStore,再刷写到 StoreFile,最后删除旧的 Hlog 文件,开始为用户提供服务。

StoreFile 的合并与分裂

  • 随着 StoreFile 数量增加,达到预先设定的阈值后,系统会触发合并操作,将多个 StoreFile 合并成一个大的 StoreFile
    • 每次刷写都生成一个新的 StoreFile,数量太多,影响查找速度。
    • 因此系统会调用 Store.compact() 把多个 StoreFile 合并成一个大文件。
    • 合并操作比较耗费资源,因此只有 StoreFile 文件数量达到一个阈值才启动合并操作。
  • 单个 StoreFile 过大时,又触发分裂操作,1个父 Region 被分裂成两个子 Region。

SotreFile 的合并和分裂过程

HLog 工作原理

分布式环境必须要考虑系统出错。HBase 采用 HLog 保证系统恢复。

  • HBase 系统为每个 Region 服务器配置了一个 HLog 文件,它是一种预写式日志(Write Ahead Log)
  • 用户更新数据必须首先写入日志后,才能写入 MemStore 缓存,并且,直到 MemStore 缓存内容对应的日志已经写入磁盘,该缓存内容才能被刷写到磁盘
  • Zookeeper 会实时监测每个 Region 服务器的状态,当某个 Region 服务器发生故障时,Zookeeper 会通知 Master
  • Master 首先会处理该故障 Region 服务器上面遗留的 HLog 文件,这个遗留的 HLog 文件中包含了来自多个 Region 对象的日志记录
  • 系统会根据每条日志记录所属的 Region 对象对 HLog 数据进行拆分,分别放到相应 Region 对象的目录下,然后,再将失效的 Region 重新分配到可用的 Region 服务器中,并把与该 Region 对象相关的 HLog 日志记录也发送给相应的 Region 服务器
  • Region 服务器领取到分配给自己的 Region 对象以及与之相关的 HLog 日志记录以后,会重新做一遍日志记录中的各种操作,把日志记录中的数据写入到 MemStore 缓存中,然后,刷新到磁盘的 StoreFile 文件中,完成数据恢复

共用日志优点:提高对表的写操作性能;缺点:恢复时需要分拆日志

HBase实际应用中的性能优化方法

  • 行键(Row Key)
    行键是按照字典序存储,因此,设计行键时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。

  • InMemory
    创建表的时候,可以通过 HColumnDescriptor.setInMemory(true) 将表放到 Region 服务器的缓存中,保证在读取的时候被 cache 命中。

  • Max Version
    创建表的时候,可以通过 HColumnDescriptor.setMaxVersions(int maxVersions) 设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置 setMaxVersions(1)

  • Time To Live
    创建表的时候,可以通过 HColumnDescriptor.setTimeToLive(int timeToLive) 设置表中数据的存储生命期,过期数据将自动被删除,例如如果只需要存储最近两天的数据,那么可以设置 setTimeToLive(2 * 24 * 60 * 60)


Comments

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×