介绍

HBase是什么?

HBase 官网: http://hbase.apache.org/

Apache HBase™Hadoop数据库,是一个分布式、可伸缩、大数据存储区。

当需要随机、实时读/访问大数据时,请使用Apache HBase™ 。 该项目的目标是在商用硬件集群之上托管非常大的表----数十亿行X百万列Apache HBase是一个开源的、分布式的、版本化的、非关系的数据库,它参考了GoogleBigtable。 正如Bigtable利用Google文件系统提供的分布式数据存储一样,Apache HBaseHadoopHDFS之上提供了类似Bigtable的功能。

定义: HBaseHadoop Database,是一个高可靠性、高性能、面向列族、可伸缩、实时读写的分布式NOSQL数据库。

作用:主要用来存储非结构化、半结构化和结构化的松散数据(列式存储的NoSQL 数据库)利用Hadoop HDFS作为其文件存储系统,利用Zookeeper作为其分布式协同服务。正常情况下,HBase不依赖于YARN,用到的时候可以随时开启。从技术上讲, HBase实际上更像是数据存储不是数据库,因为它缺少RDBMS中的许多功能,例如字段类型,二级索引,触发器和高级查询语言等。

为什么要用HBase?——从 MySQL 分库分表的痛点说起

当 MySQL 单表数据量达到亿级甚至十亿级时,查询和写入效率会急剧下降,这几乎是所有互联网业务在高速增长期都会遇到的瓶颈。

为了突破这个瓶颈,大家最先想到的方案就是分库分表:先做垂直分库,把用户、商品、订单等不同业务的表拆分到不同服务器;垂直拆分满足不了需求后,再做水平分库分表,比如将订单表按照订单号 Hash 取模的方式,分散到多台服务器上,让每台机器只承担一部分数据的读写压力。

但这种方案看似解决了问题,实则是一种 “治标不治本” 的权宜之计 —— 它不仅需要牺牲 MySQL 原本的诸多特性(比如外键关联、单个数据库里面的跨行跨表的事务。),更在可伸缩性可运维性上埋下了巨大隐患。当数据量和并发量增长到数千台服务器的规模时,分库分表的弊端会被无限放大,具体体现在以下三点:

扩容不得不 “翻倍式” 操作,资源严重浪费

首先,是资源使用很浪费。当服务器性能出现瓶颈需要扩容 的时候,我们常常只能采取“ 翻倍 分库增加服务器的方案。就以前面举的订单表为例,我们通过把订单号“ 上个 4 ,拆分 到 4 个不同的服务器的数据库里。而随着我们承接的订单越来越多,每天 SQL 查询的请求越来越多,服务器的峰值 CPU可能超过了 60% 。为了安全起见,我们希望对服务器进行扩容,让峰值 CPU 控制在 40% 以下。但是这个时候,我们没办法只是增加 4 * 0.6 / 0.4 - 4 = 2 台服务器,而是不得不
增加 4 台服务器。

数据倾斜难以避免,负载均衡成奢望

分库分表的效果完全依赖于初期的数据分片设计,但业务的变化往往超出预期。比如电商的 “双十一” 大促,部分热门商品的订单量会呈指数级增长,很容易导致对应分片的服务器负载暴增,而其他分片的服务器却处于空闲状态,出现 “忙的忙死,闲的闲死” 的情况。即便初期分片设计再精细,也无法应对突发的业务波动,最终导致整个集群的负载均衡失控。人肉运维成本高,故障恢复效率低

MySQL 集群里,我们可以对每个服务器都准备一个高可用的备份,避免一出现故障整个集群就没法用了。但是此时,我们的运维人员仍然需要立刻介入,因为这个时候系统是多了一个“ 单点 的,我们需要手工添加一台新的服务器进入集群,同步到最新的数据。
总结
传统关系型数据库(如 MySQL)痛点 HBase 的解决方案
存储容量有限,单表数据量达到亿级后性能急剧下降 基于 HDFS 分布式存储,单表可以轻松支撑百亿行、TB/PB 级数据
扩展困难,横向扩容需要复杂的分库分表操作 自动分片和负载均衡,扩容只需要加机器,对业务透明
面向行存储,查询少量列时也要读取整行数据,IO 成本高 面向列族存储,按需读取列数据,大幅降低 IO 开销
不适合高并发的随机读写场景 支持百万级 QPS (Queries Per Second,每秒查询率)的随机读写,适合高频次的点查和批量写入
对海量历史数据的存储和查询效率低 支持时间序列数据的版本管理,历史数据可以高效存储和回溯

HBase的特点

  • 强大的一致读/写:HBase不是最终一致性”,而是“强一致性”DataStore。它非常适合高速计数器聚合等任务。
  • 自动分片:HBase表通过region分布在群集上,并且随着数据的增长,region会自动分割和重 新分配。
  • 自动的RegionServer故障转移。
  • Hadoop/HDFS集成:HBase支持HDFS作为其分布式文件系统。
  • MapReduceHBase支持通过MapReduce进行大规模并行处理,将HBase用作源和宿HBASE->MR->HDFS   HBASE->MR->HBASE   HDFS->MR->HBASE
  • Java客户端APIHBase支持易于使用的Java API以进行编程访问。
  • Thrift/REST APIHBase还支持非Java前端的ThriftREST
  • 块缓存和布隆过滤器:HBase支持块缓存和布隆过滤器,以实现大容量查询优化。
  • 运维管理:HBase提供内置网页,用于运维监控和JMX指标。
  • HBase不支持行间事务 HBase支持行内事务

数据模型

逻辑上, HBase 的数据模型同关系型数据库很类似,数据存储在一张表中,有行有列。但从底层物理存储结构(Key-Value )来看,HBase 更像一个 Map
逻辑结构
物理存储结构

这里男和女是两个版本的数据(t1,t2)

数据定位

row key

timestamp

CF1

CF2

CF3

11248112

t3

CF1:q2=val3

CF2:m1=val1

CF3:k3=val3

t2

CF1:q2=val2 CF1:q3=val3

t1

CF1:q2=val1

rowkey CF1:q2 获取最新数据

rowkey , CF1:q2, t1 四维数据库,获取指定列族指定列指定时间戳的数据

rowkey 列族 列名 时间戳 四个纬度

重要概念

NameSpace

命名空间,相当于关系型数据库中的 database ,每个命名空间下有多个表。Hbase 默认自带的命名空间 hbase 和 default; hbase 中存放的是 HBase 内置的表, default 是用户默认使用的命名空间。

Region

类似关系型数据库的表,不同之处在于 HBase 定义表时只需要声明列族,不需要声明具体的列。列可以动态的按需要指定;HBase 更加适合字段经常变更的场景。开始创建表是一个表对应一个region ,当表增大到一定阈值时会被拆分为两个region

Row

HBase 表中的每行数据被称为 Row ,由一个 RowKey 和多个Cell组成,数据是按照 RowKey的字典顺序升序排序 存储的,并且查询时一般根据RowKey进行检索。RowKey决定一行数据,是一行数据的唯一标识 。它只能存储64k的字节数据(UTF-8编码格式下21845.33多个汉字) ,一个英文字符占一个字节(无论是UTF-8还是GBK)。在能够表达清楚业务需求的情况下,尽可能短一些。这是因为如果一行数据中有10列,那么row key会被存储10次。

Column

  • 列是由列族(Column Family)和列限定符(Column Qualifier)进行限定。HBase表中的每个列都归属于某个列族,列族必须作为表模式(schema)定义的一部分预先给出。create ‘test’, ‘course’;
  • 列名以列族作为前缀,每个“列族”都可以有多个列成员(column);如course:math, course:english, 新的列族成员(列)可以随后按需、动态加入;
  • 权限控制、存储以及调优都是在列族层面进行的;
  • HBase把同一列族里面的数据存储在同一目录下,由几个文件保存。
  • 列族理论上可以有任意多个,但是通常在一个表中使用的列族数在3个以内。
  •  列族名和列描述符在见名知意情况下,尽可能的短一些。

Cell

  • 某行中的某一列被称为Cell(单元格),由行和列的坐标交叉决定。
  • 具体是由{rowkey,column family:column qualifier,time stamp}确定单元格。
  • Cell是是有版本的。
  • Cell中没有具体的类型,全部是字节码的形式(字节数组)存储。

TimeStamp

  • 用于标识数据的不同版本(version)。
  • 在HBase每个cell存储单元对同一份数据有多个版本,根据唯一的时间戳来区分每个版本之间的差异,不同版本的数据按照时间倒序排序,最新的数据版本排在最前面。
  • 每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,值为写入HBase的时间。
  • hbase可以容忍不同regionserver之间的时间差30s,否则失败。注意做时间同步。

架构

hbase:meta(目录表)

目录表hbase:meta作为HBase表存在,并从hbase shelllist(类似show tables)命令中过滤掉,但实际上是一个表,就像任何其他表一样。hbase:meta表(以前称为.META.),保有系统中所有region的列表。 hbase:meta位置信息存储在zookeeper中。 hbase:meta表是所有查询的入口。

hbase:meta表结构如下:

key

        region的key,结构为: [table],[region start key,end key],[region id] 

Values:

        info:regioninfo(当前region序列化的HRegionInfo实例)

        info:server(包含当前regionRegionServerserver:port

        info:serverstartcode(包含当前region的RegionServer进程的开始时间)

当表正在拆分时,将创建另外两列,称为info:splitAinfo:splitB。 这些列代表两个子region。 这些列的值也是序列化的HRegionInfo实例。 region分割后,将删除此行。

Client

hbase:meta

tablea,,100,node2

hbase:meta

tablea,101,200,node3

hbase:meta

tablea,201,300,node5

hbase:meta      tablea,301,400,node237

hbase:meta

tablea,401,500,node24

hbase:meta

tablea,501,,node896

包含访问HBase的接口并维护cache来加快对HBase的访问。

HBase客户端查找关注的行范围所在的regionserver它通过查询 hbase:meta表来完成此操作。在找到所需的region之后,客户端与提供该regionRegionServer通信,而不是通过Master,并发出读取或写入请求。此信息缓存在客户端中,以便后续请求无需经过查找过程。如果Master的负载均衡器重新平衡或者由于regionserver宕机,都会重新指定该regionregionserver。客户端将重新查询目录表以确定用户region的新位置。

通过Admin进行管理功能的实现。

空键意义

空键用于表示表开始和表结束。具有空开始键的region表中的第一个region(如tablea,,100,node2)。具有结束键的region表中的最后一个region(如tablea,501,,node896)。如果某个region同时具有空开始和空结束键,则它是表中唯一的region

Zookeeper

  • 保证任何时候,集群中只有一个活跃master
  • 存贮所有Region的寻址入口,也就是hbase:meta表的位置
  • 实时监控Region server的上线和下线信息,并实时通知Master
  • 存储HBaseschematable元数据

Master

  • Region server分配region
  • 负责Region Server的负载均衡
  • 发现失效的Region server并重新分配其上的region
  • 管理用户对table的增删改操作DDL,不是对自定义表中的数据的增删改(DML

RegionServer组成

  • Region server维护region,处理对这些regionIO请求(get putdelete)
  • Region server负责切分在运行过程中达到阈值的region
  • 负责storefile文件的合并

WAL(HLog)

由于数据要经MemStore排序后才能刷写到HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入MemStore中。所以在系统出现故障的时候,数据可以通过这个日志文件重建。

Region

  • HBase自动把表水平划分成多个区域(region),每个region会保存一个表里面某段连续的数据(每条记录都有一个行键,按照行键字典序排列)
  • 每个表一开始只有一个region随着数据不断插入表, region不断增大,当增大到一个阈值的时候, region就会等分为两个新的region(裂变)
  • 当table中的行不断增多,就会有越来越多的region。这样一张完整的表被保存在多个Regionserver 上。
  • 一个region由一个或多个store组成,在一个region内部一个store对应一个CF(列族)
  • HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的HRegion可以分布在不同的 HRegion server上。 HRegion由一个或者多个Store组成,每个store保存一个 columns family。每个Store又由一个memStore0至多个StoreFile组成。如图: StoreFileHFile格式保存在HDFS上。

MemStore StoreFile

  • store包括位于内存中的memstore和位于磁盘的storefile
  • 写操作先写入memstore,当memstore中的数据达到某个阈值,hregionserver会启动flush 进程写入storefile,每次写入形成单独的一个storefile
  • storefile文件的数量增长到一定阈值后,系统会进行合并(minormajor compaction), 在合并过程中会进行版本合并和删除工作,形成更大的storefile
  • 当一个region所有storefile的大小超过一定阈值后,会把当前的region分割为两个,并由 hmaster分配到相应的regionserver服务器,实现负载均衡
  • 客户端检索数据,先找blockcache(查询缓存),找不到再找memstore,还找不到再去找 storefile

BlockCache

读缓存,每次查询出的数据会缓存在BlockCache中,方便下次查询。

RegionServer管理

给RegionServer赋值region

hbase启动的时候, region通过如下步骤赋值给regionserver

  1. 系统启动的时候, master调用AssignmentManager(赋值管理器)
  2. AssignmentManager在hbase:meta中查找已经存在的region条目
  3. 如果region条目依旧是正确的(比如说regionserver依然在线),就保留该赋值信息
  4. 如果赋值不正确,就调用LoadBalancerFactory对region进行赋值。负载平衡器将region赋值给一个regionserver。
  5. 在regionserver打开region的时候,使用regionserver的开始更新hbase:meta中regionserver的赋值。

当客户端访问的时候, regionserver失败的时候:

  1. 由于regionserver宕机, region立即不可用
  2. master检测到该regionserver的失败
  3. 认为region的赋值不正确,使用启动顺序的流程重新给region赋值
  4. 正在进行的查询会重试,而不是丢失。
  5. 在下述时间内操作会转移到新的regionserver:zookeeper session timeout+split time+assignment/replay time

过程示例

Hbase:meta表中的数据:

psn_region1  endkey:rk01

psn_region2  startkey:’rk101’ ek:’rk102’ -- >regionserver3

  1. client->zks,获取到hbase:meta表所在的regionserver
  2. client->regionserver ,获取rk101对应的region: psn- region2,从psn-region2中获取它所在的regionserver:regionserver3
  3. client->regionserver3:从regionserver3服务器中找到对应的psn-region2并获取数据。如果在获取的途中regionserver3down了, Master重新为psn-region2赋值,比如重新赋值到regionserver2,client重新请求regionserver2.

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐