HBase初步学习

什么是HBase

HBase是一个面向列式存储的分布式数据库,底层实现基于HDFS实现,集群管理基于ZooKeeper实现,具有良好的分布式架构设计,为海量数据存储的快速存储、随机访问提供了可能,基于数据副本机制和分区机制,可以轻松实现在线扩容、缩容和数据容灾,是大数据 Key-Value 数据结构存储的常用解决方案

HBase模块组成

HBase可以将数据存储在本地文件系统,也可以存储在HDFS文件系统,在生存环境中,HBase一般运行在HDFS上,以HDFS作为基础的存储设施,HBase通过HBase Client提供的Java API访问HBase数据库,已完成数据的写入和读取,HBase集群主要由HMasterRegion ServerZooKeeper组成

  • HMaster

    • 负责管理RegionServer,实现负载均衡

    • 管理和分配Region,比如在Region Split时分配新的Region,在RegionServer退出时迁移内部的Region到其他RegionServer

    • 管理NamespaceTable的元数据(实际存储在HDFS上)

    • 权限控制

  • RegionServer

    • 存放和管理本地Region

    • 读写HDFS,管理Table中的数据

    • ClientHMaster中获取元数据,找到RowKey所在的RegionServer进行读写数据

  • ZooKeeper

    • 存放整个HBase集群的元数据以及集群的信息状态

    • 实现HMaster主从节点的Failover

HBase数据模型

HBase是一个面向列式存储的分布式数据库。HBase的数据模型与BigTable十分相似。在 HBase表中,一条数据拥有一个全局唯一的键RowKey和任意数量的列Column,一列或多列组成一个列族Column Family,同一个列族中列的数据在物理上都存储在同一个 HFile 中,这样基于列存储的数据结构有利于数据缓存和查询。 HBase 中的表是疏松地存储的,因此用户可以动态地为数据定义各种不同的列。HBase中的数据按主键排序,同时,HBase会将表按主键划分为多个Region存储在不同RegionServer上,以完成数据的分布式存储和读取。

HBase根据列成来存储数据,一个列族对应物理存储上的一个HFile,列族包含多列列族在创建表的时候被指定。

  • ColumnFamily

    ColumnFamily即列族,HBase基于列族划分数据的物理存储,一个列族可以包含多列

    一般同一类的列会放在一个列族,每个列族都有一组存储属性:

    • 是否应该缓存在内存中

    • 数据如何被压缩或行键如何编码等

    HBase在创建表的时候就必须指定列族,列族最好小于等于3个,过多不方便管理和索引

  • RowKey

    RowKey的概念和传统关系型数据库中的主键相似,HBase使用RowKey来唯一标识某行的数据

    访问HBase数据的方式有三种:

    • 基于RowKey的单行查询

    • 基于RowKey的范围查询

    • 全表扫描查询

  • Region

    HBase将表中的数据基于RowKey的不同范围划分到不同的Region上,每个Region都负责一定范围的数据存储和访问

    每个表开始只有一个Region,随着数据不断插入表,Region不断增大,当增大到一个阙值的时候,Region就会分成两个新的Region

    另外,RegionHBase中分布式存储和负载均衡的最小单元,不同的Region分布在不同的RegionServer

    这样就方便了大量数据下的并发操作,访问数据速度不会有太大降低

  • TimeStamp

    TimeStamp是实现HBase多版本的关键,在HBase中,使用不同的TmeStamp来标识相同RowKey对应不同的版本的数据,相同的RowKey的数据按照TimeStamp倒叙排列,默认查询最新版本,当然也可以用户指定查询

底层设计

Master

主要的进程,具体实现类为HMaster

通常部署在namenode

主要包含3个部件

  1. 负载均衡器

    读取Meta表了解Region的分配,通过zk了解RS的启动情况,每5分钟调控一次分配平衡

  2. 元数据表管理器

    负责管理Meta表的数据

  3. MasterProcWAL预写日志管理器

    负责管理Master自己的预写日志,如果宕机,让BackUpMaster读取日志数据

    本质是写数据到HDFS,文件到达32M或一小时滚动,当操作执行到Meta表之后删除WAL

PS:客户端只有在操作元数据时才会和Master建立连接,也就是getAdmin(),操作其他表数据时,是直接通过zookeeperRegion互动,也就是getTable()

RegionServer

主要的进程,具体实现类为HRegionServer

通常部署在dataNode

MemStore的数量取决RegionServer管理了多少个Store

Client写入数据时,会先写入MemStore,然后再写入Store中(这一步主要的为了根据RowKey排序),所以WAL预写日志就是为了防止MemStore数据还没写入到StoreMaster就挂了而准备的

除了一些必要的组件,还会启动一些线程监控必要的服务:

  1. Region拆分

  2. Region的合并

  3. MemStory书写

  4. WAL预写日志的滚动

写流程

写流程从客户端创建连接开始,到最终刷写落盘道HDFS上结束

先写入WAL的原因是数据在MemStore会排序并保存一段时间,存内存是不安全的

数据在写入MemStore之后会返回写入成功的ACK,此时宕机可以通过WAL找回

写流程顺序正如API编写顺序

  1. 创建HBase重量级连接

  2. 首先访问Zookeeper,获取HBase:Meta表位于哪个RegionServer

  3. 访问对应的RegionServer,获取HBase:Meta表,将其缓存到连接中,作为连接属性MetaCache,由Meta表格具有一定的数据量,导致创建连接比较慢

    之后创建连接获取Table,这是一个轻量级连接,只有在第一次创建的时候会检查表格是否存在访问RegionServer,之后在获取Table时不会访问RegionServer

  4. 调用TablePut方法写入数据,此时还需要解析RowKey,对照缓存MetaCache,查看具体写入的位置有有哪个RegionServer

  5. 将数据顺序写入(追加)到WAL,此处写入是直接落盘的,并设置专门的线程控制WAL预写日志的滚动

读流程

读流程从客户端创建连接开始,到合并数据返回客户端结束

读流程同写流程差不多

  1. 创建Table对象发送Get请求

  2. 优先访问BlockCache,查找是否之前读取过,并且可以读取HFile的索引信息和布隆过滤器

  3. 不管读缓存是否已经有数据(可能已经过期了),都需要再次读取写缓存和Store中的文件

  4. 最终将所有读取到的数据合并版本,按照Get的要求返回即可

RowKey的设计

HBaseRowKey可以唯一表示一行记录,在HBase查询时有以下方式:

  1. 通过Get方式,指定RowKey获取唯一记录

  2. 通过Scan方法,设置startRowstopRow进行范围匹配

  3. 全表扫描

RowKey在增删改查中充当主键的作用,它可以是任意字符串,在HBaseRowKey会保存为字节数组

HBase中数据是按照RowKeyASCII字典顺序进行全局排序,因此,在设计RowKey时,要充分利用并意识到这个特性

HBase表的数据是按照RowKey来分散到不同的Region中的,不合理的RowKey设计会导致热点问题,大量的Client访问集群的一个或极少数节点,而其他节点普遍处于空闲状态

参数调优

  1. Zookeeper会话超时时间调整

    hbase-site.xml

    属性:zookeeper.session.timeout

    解释:默认值为90000毫秒(90s),当某个RegionServer挂掉了,90sMaster上能察觉到,可适当减少此值,尽可能快的检查到RegionServer故障,可调整至20-30s

    同时可时代调整Client重试时间和重试次数

    hbase.client.pause (默认100ms)

    hbase.client.retries.number (默认15次)

  2. 设置RPC监听数量

    hbase-site.xml

    属性:hbase.regionserver.handler.count

    解释:默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值

  3. 手动控制Major Compaction

    hbase-site.xml

    属性:hbase.hregion.majorcompaction

    解释:默认值为604800000秒(7天),MajorCompaction的周期,若关闭自动MajorCompaction,可将其设置为0

    如果关闭记得手动合并,因为大合并非常有意义

  4. 优化HStore文件大小

    hbase-site.xml

    属性:hbase.hregion.max.filesize

    解释:默认值10737418240 (10G) ,如果需要运行HBaseMR任务,可以减小此值,因为应该region对应一个map任务,如果单个region过大,会导致map任务执行时间过长,该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个HFile

  5. 优化HBase客户端缓存

    hbase-site.xml

    属性:hbase.client.write.buffer

    解释:默认值2097152 bytes (2M),用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存,反之则反之,一般我们需要设定一定的缓存大小,以达到减少RPC调用次数的目的

  6. 指定scan.next扫描HBase获取的行数

    hbase-site.xml

    属性:hbase.client.scanner.caching

    解释:用于指定scan.next方法获取的默认行数,值越大,消耗内存越大

  7. BlockCache占用RegionServer堆内存的比例

    hbase-site.xml

    属性:hfile.block.cache.size

    解释:默认0.4,读请求比较多的情况下,可适当调大

  8. MemStore占用RegionServer堆内存的比例

    hbase-site.xml

    属性:hbase.regionserver.global.memstore.size

    解释:默认0.4,写请求比较多的情况下,可适当调大

参考

文章1:https://zhuanlan.zhihu.com/p/522104503

文章2:https://www.pianshen.com/article/1586364877

视频:https://www.bilibili.com/video/BV1PZ4y1i7gZ