HBase存储原理探究

我们知道RDBMS底层使用B树、B+树的存储结构,hbase使用LSM树(log-structured merge tree),对于单表存储容量,hbase可以依托其平滑的扩展性,满足RDBMS的瓶颈。他们的设计思想的差距体现在哪里呢?本文将对其分析:

1.数据结构

  • B+树

    保持数据稳定有序,自底向上插入(与二叉树相反),通过最大化每个内部节点的子节点数目来减少树的高度,不经常发生平衡操作(eg.2-3B树,可能有2或3个子节点/内部节点,不像自平衡二叉树经常重新平衡),增加效率。

  • LSM树

    思想:划分不同等级的树。
    eg.二级树,一份索引数据由2棵树(内存,可能是B树、AVL树等+磁盘,是B树)组成。数据先插入内存的树,超阈值,从左至右遍历,合并内存中叶子节点+磁盘中叶子节点,达到磁盘存储页大小,持久化到磁盘+更新父节点对叶子节点指针。磁盘的叶子节点(非叶子节点也被缓存到内存中)合并后,复制一份旧数据,与内存的数据一起顺序写到磁盘。 磁盘树过大(数据量过大),合并会变慢。
    解决手段:建立层次。eg.内存的树为C0,磁盘的树为C1,C2,C3,…,Cn,合并顺序(C0,C1),(C1,C2)……时间越长,flush越多,产生很多存储文件,而所有数据按key排序,不用重排

  • 区别:

    使用硬件的方式,特别是磁盘。

    磁盘角度: RDBMS通常都是寻道型(寻道速度每年大概提升5%),由B或B+树结构决定,log(N)。LSM-Tree是传输型(cpu、ram和磁盘空间每18~24个月翻番),在大规模下,传输比寻道高效。

  • 优缺点:

    无太多更新时,B+树工作得很好,以较繁重的优化保证较低的访问时间。数据被越快越多地放到随机位置,页面会变得越碎片化。最终,数据传入速度可能超过优化进程重写现存文件的速度。改删以磁盘寻道速率级别进行,受限于最差的那个磁盘性能。
    LSM-Tree以磁盘传输速率级别进行,使用日志文件和一个内存存储结构把随机写转换为顺序写,且读写操作独立,不产生竞争。可更好的扩展大规模数据,保证较一致的插入速率。

2. 底层持久化

  • 架构

    工作流程: 客户端先连接zookeeper qurom(持有-ROOT-Region的服务器名,访问拥有它的regionserver),得到持有对应行键的.META.表region的服务器名。两个操作都会被缓存下来,最后根据.META.服务器检索包含给定行键的region所在服务器。

    启动hbase时,hmaster负责把region分配给每个hregionserver,包括-ROOT-和.META.表。

  • 结合经典的架构图理解

    hregionserver打开region,创建对应的hregion对象。当hregion被打开,就会为每个hcolumnfamily创建一个store实例(包含多个storefile实例(对hfile存储文件的简单封装)+一个memstore+一个由hregionserver共享的hlog实例(WAL相关类))。

  • HDFS文件

    flush命令将内存数据写入存储文件,否则得等到超过配置的flush大小。

    • hbase文件:①hbase根目录下;②表目录下。
    • 表:每个表都有自己的目录:/hbase/表名/.tableinfo(保存HTableDescriptor序列化后的内容+元数据信息,eg.查表定义时读取)、/hbase/表名/.tmp(中间数据,eg.表被改动时)
    • region:region因容量大小需split,会创建与之对应的splits目录(几秒),创建成功后被移入表目录下形成两个新的region。WAL的splitting和region的splitting有明显区别。
      eg.USER_TEST_TABLE,AAA-AAA11110UC1,1364437081331.68b8ad74920040ba9f39141e908c67.,其中USER_TEST_TABLE,AAA-AAA11110UC1,1364437081331是region前部分,.68b8ad74920040ba9f39141e908c67.是哈希)。
      .META.表的region命名规则和用户表不同,它使用Jenkins hash对region名称编码,可保证其名称总是合法。
      查看HBase表在HDFS中的文件结构
      HBase 在HDFS 上的目录树
  • region切分

当一个region内的存储文件大于阈值时,该region会split成两个。regionserver通过在父region内创建切分目录,准备生成新的region(多线程)——包括新的region目录+文件引用,完成后把两新region目录移到表目录,然后更新.META.表,指明该region已被切分+子region名称、位置等。 启动合并,异步将存储文件从原始region写成两半,原子性的取代引用文件。原始region最终被清除(.META.表+磁盘),master接到split通知,通过负载均衡将新region移动到其他服务器。split的步骤都会通过zookeeper追踪,允许服务器出错,其他进程知晓region状态。

  • 合并

    memstore的flush操作逐步增加磁盘上的文件数目,足够多时合并成规模更少但更大的文件。

    两种类型:小合并(minor compaction,将一些小文件合并成更大的文件)和大合并(major compaction,将所有文件合并成一个)。
    ①所有小于最小合并阈值的都会被包含进合并列表(达到单次合并的文件数上限之前)。算法会保证老文件先被合并+确保总能够选出足够文件合并。
    ②当memstore被flush到磁盘或执行compact 或 major_compact 或 API调用,会触发检查。前两者在服务端会先检查是否应该大合并,后两者会强制大合并。

  • hfile

    一种文件存储格式的抽象,有v1和v2版,以下围绕v1讲解。

datadatametametafile infodata index meta indextrailer

一个data包含:magic、keyvalue、keyvalue …. 每个block包含一个magic头和一系列序列化的keyvalue对象。文件是变长的,file info和trailer是定长的块。trailer会被写入文件末尾,包含指向其他block的指针,index block记录了data和meta block的偏移。block大小通过HColumnDescriptor配置,默认64KB(官方推荐8KB-1MB)。

若主要顺序访问,应设大一点的block(会降低随机访问性能,有大量数据需解压)。 若主要随机访问,应设小一点的block(需更多内存保存block index,创建文件变慢,因写入block后需对压缩编码器flush)。
使用压缩算法,block大小不可控。默认,HDFS的block有64MB,是hfile的1000倍。他们二者没有关系,HDFS只看到hbase的二进制文件,不知道存储了什么。

  • keyvalue
    keyvalue结构-加粗为key部分

    key length|value length |row length|row|column family length|column family|column qualifier|time stamp|key type| value

    标识key和value的长度,来保证数组可忽略key,直接访问value。key包含了很多维度的信息,处理小value值时,要尽量让key很小。选择一个短的rowkey和column family(1字节的列族名称,qualifier也要短)来控制二者大小比例。压缩有助于缓解该问题,包含重复数据压缩率会比较高,且存储文件的keyvalue排好序,可让类似的key靠在一起。

3 . 数据压缩

  • 支持的压缩算法

    LZO:速度快,无损算法,线程安全,基于GPL协议(hbase基于Apache协议),故需自行安装。
    GZIP(GUNzip),相比LZO压缩率更高但速度更慢。
    SNAPPY,高速压缩速度和合理压缩率,比ZLIB快,不兼容其他压缩格式。

  • 配置

    先确保已安装压缩算法库。建表默认不压缩,值为NONE。对已存在的表重设压缩,需先下线表,修改压缩算法,最后上线表。

describe 'test'
disable 'test'
alter 'test',{NAME=>'cf1',COMPRESSION=>'SNAPPY'}
describe 'test'
enable 'test'

4. 预写日志

为避免产生过多小文件,regionserver在未收集到足够数据flush到磁盘前,会一直把它保存在内存中(宕机丢失数据)。hbase采用WAL(write-ahead log)策略: 每次更新前,先写到日志中。类似MySQL的bin-log,WAL会记录数据的所有变更,当内存产生问题,通过日志恢复到宕机前的状态。WAL失败,则认为整个操作失败。

  • 流程

    ①客户端发送更新操作,包装keyvalue对象,通过RPC发送,到达具有对应region的某个hregionserver;
    ②keyvalue对象到达后,根据行键到达对应的hregion,数据先写入WAL,再存入响应的memstore中;
    ③memstore达到一定大小或过了特定时段后,数据会异步持久化到文件系统。期间数据都存在内存,WAL可保证数据不丢失。
    日志存在HDFS上,不需要失败的服务器参与,其他服务器都能打开回放。

  • 日志回放
    WAL保存各种操作日志,当服务器出现错误进行恢复,其恢复过程称为日志回放。

    • 公用日志文件:每个regionserver的所有修改操作都写入同一个HLog的日志文件内(该设计源自底层文件系统:若每个region单独保存日志,同时并发写入太多文件+日志切换会降低可扩展性。master必须等待宕机机器的所有日志都分离完毕才可重新部署上面的region)
    • 日志切分:master检查.logs目录是否存在日志。日志回放更新操作(put、delete、increment,其他操作不关心)。 回放前需按region剥离出来。
    • 切分过程: 读取日志,按记录所属region分组,将其(更新操作)保持在目标region附近的一个文件中,用于后续恢复。现有版本使用zookeeper,当master确认某日志就绪,regionserver会进行竞争性选举,选出一个读取切分该日志文件。切分成功后,对应的文件会被移入实际的region目录中。
  • 日志一致性
    日志保证数据安全,最好能长时间处于打开状态。为能读到服务器crash时最后写入的位置或尽可能接近该位置,需要feature:append支持。

“尽信书不如无书”,坚持了解每个开源项目代码逻辑的实现才是王道。


参考:
《HBase企业应用开发实战》


作者: @nanphonfy
转载出处 : http://blog.csdn.net/nanphonfy


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值