简介:

HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。

是 Apache Hadoop 的数据库,是建立在 HDFS 之上,被设计用来提供高可靠性、高性能、列存储、可伸缩、多版本的 NoSQL的分布式数据存储系统,实现对大型数据的实时、随机的读写访问。

特点:

HBase 依赖于 HDFS 做底层的数据存储,BigTable 依赖 Google GFS 做数据存储

HBase 依赖于 MapReduce 做数据计算,BigTable 依赖 Google MapReduce 做数据计算

HBase 依赖于 ZooKeeper 做服务协调,BigTable 依赖 Google Chubby 做服务协调

下图描述Hadoop EcoSystem中的各层系统。其中,HBase位于结构化存储层,Hadoop HDFS为HBase提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定服务和failover机制。

此外,Pig和Hive还为HBase提供了高层语言支持,使得在HBase上进行数据统计处理变的非常简单。 Sqoop则为HBase提供了方便的RDBMS数据导入功能,使得传统数据库数据向HBase中迁移变的非常方便。

BI:商业智能化,报表                   RDBMS:传统数据库

Zookeeper:协作                        Avro:反序列化

基础是HDFS文件系统                

Hbase是将hdfs封装,引入列式存储,最终还是存储在HDFS

HBase存在block

应用场景:

1、半结构化或非结构化数据

对于数据结构字段不够确定或杂乱无章很难按一个概念去进行抽取的数据适合用 HBase。而且 HBase 是面向列的,HBase 支持动态增加字段

2、记录非常稀疏

RDBMS 的行有多少列是固定的,为 null 的列浪费了存储空间。而 HBase 为 null 的 Column是不会被存储的,这样既节省了空间又提高了读性能。

3、多版本数据

对于需要存储变动历史记录的数据,HBase 根据 Row key 和Column key 定位到的 Value 可以有任意数量的版本值。

4、超大数据量的随机、实时读写

HBase 会自动水平切分扩展,跟 Hadoop 的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性(MapReduce)

当数据量越来越大,RDBMS 数据库撑不住了,就出现了读写分离策略,通过一个 Master 专门负责写操作,多个 Slave 负责读操作,服务器成本倍增。随着压力增加,Master 撑不住了,这时就要分库了,把关联不大的数据分开部署,一些 join 查询不能用了,需要借助中间层。随着数据量的进一步增加,一个表的记录越来越大,查询就变得很慢,于是又得搞分表,比如按 ID 取模分成多个表以减少单个表的记录

5、查询简单

不涉及到复杂的 Join 查询,基于 RowKey 或者 RowKey 的范围查询

为什么要用Hbase?

1.HBase是基于HDFS分布式文件系统去构建的。换句话说,HBase的数据其实也是存储在HDFS上的。

2.HBase可以以低成本来存储海量的数据并且支持高并发随机写和实时查询

3.HBase还有一个特点就是:存储数据的”结构“可以地非常灵活

Hbase和HDFS的区别

HDFS是文件系统,而HBase是数据库「可以把HBase当做是MySQL,把HDFS当做是硬盘。HBase只是一个NoSQL数据库,把数据存在HDFS上」。

HBase在HDFS之上提供了高并发的随机写和支持实时查询,这是HDFS不具备的。

对比其他组件

MySQL

  • MySQL数据库我们是算用得最多了的吧?但众所周知,MySQL是单机的。MySQL能存储多少数据,取决于那台服务器的硬盘大小。以现在互联网的数据量,很多时候MySQL是没法存储那么多数据的。
  • 比如我这边有个系统,一天就能产生1TB的数据,这数据是不可能存MySQL的。(如此大的量数据,我们现在的做法是先写到Kafka,然后落到Hive中)
  • ------------------------------------------------------------------------------------------------------------------------------------------------------

Kafka

  • Kafka我们主要用来处理消息的(解耦异步削峰)。数据到Kafka,Kafka会将数据持久化到硬盘中,并且Kafka是分布式的(很方便的扩展),理论上Kafka可以存储很大的数据。但是Kafka的数据我们
  • 不会「单独」取出来,持久化了的数据,最常见的用法就是重新设置offset,做「回溯」操作
  • ------------------------------------------------------------------------------------------------------------------------------------------------------

Redis

  • Redis是缓存数据库,所有的读写都在内存中,速度贼快。AOF/RDB存储的数据都会加载到内存中,Redis不适合存大量的数据(因为内存太贵了!)。
  • ------------------------------------------------------------------------------------------------------------------------------------------------------

Elasticsearch

  • Elasticsearch是一个分布式的搜索引擎,主要用于检索。理论上Elasticsearch也是可以存储海量的数据(毕竟分布式),我们也可以将数据用『索引』来取出来,似乎已经是非常完美的中间件了。但是如果我们的数据没有经常「检索」的需求其实不必放到Elasticsearch,数据写入Elasticsearch需要分词,无疑会浪费资源。
  • ------------------------------------------------------------------------------------------------------------------------------------------------------

HDFS

  • HDFS是可以存储海量的数据的,它就是为海量数据而生的。它也有明显的缺点:不支持随机修改,查询效率低,对小文件支持不友好。

Hbase的存储结构

名称:

主键

MySQL

主键

HBase

命名空间

列簇

行键

库:命名空间 namespace

表: table

列:hbase内叫列簇 column family

htable 和 region 的关系相当于 file 和 block

列式存储

打个比方:手机会有很多的属性,每个属性都需要单独一个字段一个列来表示:手机型号、颜色、内存、处理器、价格等等;

同样是手机,不同品牌拥有的性能不一样,参数不一样,你有的我没有,这时候就有问题了,有些字段值会为空,但值为空也是占内存的,在大数据里面数据庞大,一旦为空的值增多,就会浪费内存。

普通数据库

普通数据库来描述手机字段会横向扩展,非常的长,为空的值不会忽略,依旧占用内存

ID

手机品牌

型号

颜色

内存

价格

...

1

苹果

IPhoneXR

黑色

128G

6000

...

2

苹果

IPhone13

512G

10000

...

Hbase列式存储

把每列抽出来,然后关联上Id。转换后的数据还是一行一行的。

仔细观察数据结构:是不是很像K-V存储?品牌是K,苹果是V、型号是K,IPhoneXR是V,ID单独一列(行键)

型号:IPhoneXR

ID:1

颜色:黑色

ID:1

内存:128G

ID:1

价格:6000

ID:2

品牌:苹果

ID:2

型号:IPhone13

ID:2

内存:512G

ID:2

价格:10000

对比

很明显以前我们一行记录多个属性(列),有部分的列是空缺的,但是我们还是需要空间去存储。现在把这些列全部拆开,有什么我们就存什么,这样空间就能被我们充分利用。

为什么HBase列式存储可以节省空间?

普通存储不会忽略null值,而null值又占有一定空间,数据量大的情况下会非常消耗内存

列式存储实际上就是列转行,列转行会忽略空值

HBase的Key-Value

HBase本质上其实就是 Key-Value的数据库

Key由RowKey(行键)+ColumnFamily(列族)+Column Qualifier(列修饰符)+TimeStamp(时间戳--版本)+KeyType(类型)组成,而Value就是实际上的值。

Map<String,Map<String,Object>>

          👆                👆           👆

        行键     字段(column)    值(value)

 

 修改一条数据其实上是在原来的基础上增加一个版本的,那我们要准确定位一条数据,那就得(RowKey+Column+时间戳),时间戳得足够精确,甚至精确到纳秒级

Hbase数据模型

Hbase的数据模型跟关系型数据库还是有区别的。

Hbase里面也有表、行和列的概念

        表:没什么好说的,就是一张表

        一行数据由一个行键和一个或多个相关的列以及他的值所组成

1.行键:在HBase里边,定位一行数据会有一个唯一的值,这个叫做行键(RowKey),相当于MySQL的主键,Table中的记录默认按照Row Key升序排序,每个表的行键都是一个独立的列

2.列簇:HBase的列(Column)都得归属到列簇(Column Family)中,一个Column Family中可以由任意多个Column组成,即Column Family支持动态扩展,无需预先定义Column的数量以及类型

每个列簇相当于MySQL的一张表,实际上是把MySQL多张表横向合并到一张HBase表内

3.时间戳:HBase 中通过 RowKey 和 Column 确定的为一个存储单元称为 Cell。每个 Cell 都保存着同一份数据的多个版本。版本通过时间戳来索引。

4.HBase中有两张特殊的Table,-ROOT-和.META.

        .META.:记录了用户表的Region信息,.META.可以有多个region

        -ROOT-:记录了.META.表的Region信息,-ROOT-只有一个regionØ

        Zookeeper中记录了-ROOT-表的location

通过ROOT找到META的映射关系,通过META找到表和行键对应的节点映射关系(主从)

5.Client访问用户数据之前需要首先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过client端会做cache缓存。

6.HBase Table和Region的关系,比较类似HDFS File和Block的关系,(补充:File是逻辑名字,存储在NameNode上最新版本的FSimage,Edit日志)

HBase提供了配套的TableInputFormat和TableOutputFormat API,可以方便的将HBase Table作为Hadoop MapReduce的Source和Sink

初始模型:

放入具体值: 

这张表我们有两个列族,分别是UserInfo和OrderInfo。在UserInfo下有两个列,分别是UserInfo:name和UserInfo:age,在OrderInfo下有两个列,分别是OrderInfo:orderId和OrderInfo:money。

UserInfo:name的值为:火炎焱。UserInfo:age的值为24。OrderInfo:orderId的值为23333。OrderInfo:money的值为30。这些数据的主键(RowKey)为1

再来一张我们熟悉的表对比一下:

操作hbase

        #只有新增操作,通过操作类型和时间戳建立版本管理,按照时间的先后顺序0,1,2...

        #可以通过切换版本追踪历史数据

        #可以设置最大保留实例记录数

一个列族下可以任意添加列,不受任何限制

数据写到HBase的时候都会被记录一个时间戳,这个时间戳被我们当做一个版本。比如说,我们修改或者删除某一条的时候,本质上是往里边新增一条数据,记录的版本加一了而已

注:版本是可以回退的,比如查看历史版本

如图:

现在要把这条记录的值改为40,实际上就是多添加一条记录,在读的时候按照时间戳读最新的记录。在外界「看起来」就是把这条记录改了。

 上面只说了「修改(Update)」的情况,如果要删除一条数据?实际上增删改查对于HBase来说只是标注了一个新的状态,如delete基于最新版本去查,是没有这一列的,如果回退是可以查到的

Hbase架构

1、ClientHBase Client使用HBase的RPC机制与HMaster和HRegionServer进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC

2、Client客户端,它提供了访问HBase的接口,并且维护了对应的cache来加速HBase的访问。

3、Zookeeper存储HBase的元数据(meta表),无论是读还是写数据,都是去Zookeeper里边拿到meta元数据告诉给客户端去哪台机器读写数据

4、HRegionServer它是处理客户端的读写请求,负责与HDFS底层交互,是真正干活的节点。

大致的流程:

client请求到Zookeeper,Zookeeper返回HRegionServer地址给client,client得到Zookeeper返回的地址去请求HRegionServer,HRegionServer读写数据后返回给client。

HRegionServer

HRegionServer主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。

HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。

HBase可以存储海量的数据,HBase是分布式的。所以我们可以断定:HBase一张表的数据会分到多台机器上的。

HBase是怎么切割一张表的数据的呢?那就是RowKey,对表横向切割

 一个HRegion上,存储HBase表的一部分数据。

Store是什么?

一个HBase表首先要定义列簇,列在列簇之下,列可以随意添加。

一个列簇的数据是存储在一起的,所以一个列簇的数据是存储在一个Store里边的。

Store里面有什么?

HBase在写数据的时候,会先写到Mem Store,当MemStore超过一定阈值,就会将内存中的数据刷写到硬盘上,形成StoreFile,而StoreFile底层是以HFile的格式保存,HFile是HBase中KeyValue数据的存储格式。

所以说:Mem Store我们可以理解为内存 buffer,HFile是HBase实际存储的数据格式,而StoreFile只是HBase里的一个名字。

总结:

HRegionServer是真正干活的机器(用于与hdfs交互),我们HBase表用RowKey来横向切分表

HRegion里边会有多个Store,每个Store其实就是一个列族的数据(所以我们可以说HBase是基于列族存储的)

Store里边有Men Store和StoreFile(HFile),其实就是先走一层内存,然后再刷到磁盘的结构

HMaster

HBase 的主节点,负责整个集群的状态感知、负载分配、负责用户表的元数据(schema)管理(可以配置多个用来实现 HA),HMaster 负载压力相对于 HDFS 的 NameNode会小很多。HBase 的 HMaster 其实就算是宕机一段时间也可以正常对外提供服务的(要搞清楚为什么)。

HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行,HMaster在功能上主要负责Table和Region的管理工作:

1. 管理用户对Table的增、删、改、查操作

2. 管理HRegionServer的负载均衡,调整Region分布

3. 在Region Split后,负责新Region的分配

4. 在HRegionServer停机后,负责失效HRegionServer 上的Regions迁移

HMaster会处理 HRegion 的分配或转移。如果我们HRegion的数据量太大的话,HMaster会对拆分后的Region重新分配RegionServer。(如果发现失效的HRegion,也会将失效的HRegion分配到正常的HRegionServer中)

HMaster会处理元数据的变更和监控RegionServer的状态。

#容错机制(HLog)

什么时候会发生容错?

在HRegionServer挂掉的时候,所有的region都变成不可用状态,这时候会进入HBase的容错机制

HRegionServer挂掉的原因:

1.HBase集群预留内存不足

现象:HBase RS在起来1-2min后马上挂掉

 分析:此处可知所做的操作只是HBase RS的假启动,前端看上去好像是启动成功了,但是实际上并没有真正启动。

解决思路:适当减小HBase RegionServer Maximum Memory对应的值。

 2.HBase集群时钟不同步

现象:HBase RS运行一段时间后挂掉

日志:

ERROR [B.defaultRpcServer.handler=4,queue=1,port=16000] master.MasterRpcServices: Region server slave1,16020,1494163890158 reported a fatal error: ABORTING region server slave1,16020,1494163890158: Unhandled: org.apache.hadoop.HBase.ClockOutOfSyncException: Server slave1,16020,1494163890158 has been rejected; Reported time is too far out of sync with master.Time difference of 52782ms > max allowed of 30000ms

 分析:集群中的不同机器时间差较大,HBase集群对时钟同步要求较高。

解决思路:

        查看集群中/etc/ntp.conf的server配置是否合理,

        利用service ntpd status来查看ntp的状态

        利用service ntpd start启动ntp

        利用ntpdate –u node1在三个节点立即进行时钟同步

        利用chkconfig ntpd on设置所有节点ntp服务开机自启动。

3.HBase集群zk的连接数设置过少

现象:RS运行一段时间后挂掉

ERROR [regionserver/node1/101.12.38.119:16020] zookeeper.ZooKeeperWatcher: regionserver:16020-0x3651eb7c95b0006, quorum=node1:2181,node2:2181,node3:2181, baseZNode=/HBase-unsecure Received unexpected KeeperException, re-throwing exceptionorg.apache.zookeeper.KeeperException$SessionExpiredException: KeeperErrorCode = Session expired for /HBase-unsecure/replication/rs/node1,16020,1533819219139\

分析:zookeeper的连接数设置过少,在HBase的高并发业务时会出现如上问题

解决思路:在zookeeper的配置文件zoo.cfg中添加如下自定义配置(该配置在hbase中默认值为60):添加:maxClientCnxns=600,重启zk,启动HBase。

4.HBase无法写入(无法落地存到hdfs)

日志:

java.io.IOException: Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try

分析:无法写入,3个datanode,备份数量设置的是3。在写操作时,它会在pipeline中写3个机器。默认replace-datanode-on-failure.policy是DEFAULT,如果系统中的datanode大于等于3,它会找另外一个datanode来拷贝。目前机器只有3台,因此只要一台datanode出问题,就一直无法写入成功。

处理方法:修改hdfs-site.xml文件,添加或者修改如下两项:

<property>
    <name>dfs.client.block.write.replace-datanode-on-failure.enable</name>
     <value>true</value>
</property>
 
<property>
<name>dfs.client.block.write.replace-datanode-on-failure.policy</name>
 <value>NEVER</value>
</property>

5.HBase读数据超时

日志:

ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: xxx:50010:DataXceiver error processing WRITE_BLOCK operation src: /xxx:52827 dst: /xxx:50010 java.net.SocketTimeoutException: 60000 millis timeout while waiting for channel to be ready for read. ch : java.nio.channels.SocketChannel[connected local=/xxx:50010 remote=/xxx:52827]

分析:读数据超时,出现以上错误是因为datanode的服务线程连接数都被占用,导致等待超时。

处理方法:

datanode的资源情况适当增加的服务线程数:在hdfs-site.xml增加自定义配置文件里面新增或修改dfs.datanode.handler.count,默认是10,适当加大。

增加客户端的超时时间dfs.client.socket-timeout,默认是60000ms。

增大HBase配置项中的zookeeper session timeout数值。

增加DataNode max data transfer threads至合理数值。

1.怎么知道HRegionServer没了?

2.知道没了会干什么?

3.怎么容错?

具体步骤:

每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中(HBase的日志),HLog文件定期会滚动出新的,并删除旧的文件(已持久化到StoreFile中的数据)。

1.当HRegionServer意外终止后,HMaster会通过Zookeeper感知到

2.知道没了会进行数据迁移,读取死亡节点的HLog,从HMaster重新找一个闲置的节点把数据迁移过去

3.HMaster首先会处理遗留的 HLog文件,将不同Region的Log数据进行拆分,分别放到相应region的目录下,再将失效的region重新分配

领取到这些region的HRegionServer在Load Region过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复,迁移数据后更新META

多个HMaster死了怎么办?

Master角色的主要工作就是监控所有的RegionServer实例,分配Region,HDFS垃圾回收等,

HBase中是多Master模式的,当某一个master的状态不可用之后,Zookeeper会重新选举一个Master来,

在Master失效的时候,是不影响读操作的,因为读操作时不经过Master这一层的。

读的时候直接从ZK中获取位置信息,然后链接到某个RegionServer服务进⾏行读数据

RegionServer 容错

RegionServer会定期的往ZK中发送心跳,如果间隔一段时间ZK没有收到心跳,

则Master将会该RegionServer上⾯面的Region分配到其他的RegionServer上,

通过HLog也将由Master分割并发送给RegionServer

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐