• HBase工作原理概述


                  HBase工作原理概述

                                         作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

      

     

      我们知道面向行存储的关系型数据库擅长处理查询的操作,而面向列的存储的数据库擅长统计分析数据。HBase是分布式面向列存储的数据库。

    一.HBase概述

    1>.什么是HBase

      HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护,用于支持结构化的数据存储。
    
      HBase重大事件:
        2006年Google发表BigTable白皮书     2006年开始开发HBase     2008年北京成功开奥运会,程序员默默地将HBase弄成了Hadoop的子项目     2010年HBase成为Apache顶级项目
      现在很多公司二次开发出了很多发行版本,你也开始使用了。
      HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。
      HBase的目标是存储并处理大型的数据,更具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据。   
      HBase是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用Chubby作为协同服务,HBase利用Zookeeper作为对应。

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

    2>.HBase特点

      海量存储
        Hbase适合存储PB级别的海量数据,在PB级别的数据以及采用廉价PC存储的情况下,能在几十到百毫秒内返回数据。这与Hbase的极易扩展性息息相关。正式因为Hbase良好的扩展性,才为海量数据的存储提供了便利。
      列式存储     这里的列式存储其实说的是列族(ColumnFamily)存储,Hbase是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。
      极易扩展     Hbase的扩展性主要体现在两个方面,一个是基于上层处理能力(RegionServer)的扩展,一个是基于存储的扩展(HDFS)。     通过横向添加RegionSever的机器,进行水平扩展,提升Hbase上层的处理能力,提升Hbsae服务更多Region的能力。     备注:RegionServer的作用是管理region、承接业务的访问,这个后面会详细的介绍通过横向添加Datanode的机器,进行存储层扩容,提升Hbase的数据存储能力和提升后端存储的读写能力。

      高并发(多核)     由于目前大部分使用Hbase的架构,都是采用的廉价PC,因此单个IO的延迟其实并不小,一般在几十到上百ms之间。这里说的高并发,主要是在并发的情况下,Hbase的单个IO延迟下降并不多。能获得高并发、低延迟的服务。
      稀疏     稀疏主要是针对Hbase列的灵活性,在列族中,你可以指定任意多的列,在列数据为空的情况下,是不会占用存储空间的。

    3>.HBase架构

      如上图所示,可以看出Hbase是由Client、Zookeeper、Master、HRegionServer、HDFS等几个组件组成,下面来介绍一下几个组件的相关功能。
        
      Client功能:
        Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加速Hbase的访问,比如cache的.META.元数据的信息。
    
      Zookeeper功能:
        (1)保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务
        (2)监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知HMaster关于HRegionServer上下线的信息
        (3)存储元数据的统一入口地址
    
      Hmaster功能:
        (1)监控RegionServer
        (2)处理RegionServer故障转移
        (3)处理元数据的变更
        (4)处理region的分配或转移
        (5)在空闲时间进行数据的负载均衡
        (6)通过Zookeeper发布自己的位置给客户端
    
      HregionServer功能:
        (1)负责存储HBase的实际数据
        (2)处理分配给它的Region
        (3)刷新缓存到HDFS
        (4)维护Hlog
        (5)执行压缩
        (6)负责处理Region分片
        HregionServer节点的内部组件:
          Write-Ahead logs(HLog)功能:
            HBase的修改记录,当对HBase读写数据的时候,数据不是直接写进磁盘,它会在内存中保留一段时间(时间以及数据量阈值可以设定)。
            但把数据保存在内存中可能有更高的概率引起数据丢失,为了解决这个问题,数据会先写在一个叫做Write-Ahead logfile的文件中,然后再写入内存中。
            所以在系统出现故障的时候,数据可以通过这个日志文件重建。
          HRegion功能:
            Hbase表的分片,HBase表会根据RowKey值被切分成不同的region存储在RegionServer中,在一个RegionServer中可以有多个不同的region。
          Store功能:
            HFile存储在Store中,一个Store对应HBase表中的一个列族(列簇, Column Family)。
          MemStore功能:
            顾名思义,就是内存存储,位于内存中,用来保存当前的数据操作,所以当数据保存在WAL中之后,RegsionServer会在内存中存储键值对。
          HFile:
            这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile是以Hfile的形式存储在HDFS的。
    
      HDFS功能:       
        (1)提供元数据和表数据的底层分布式存储服务       
        (2)数据多副本,保证的高可靠和高可用性 
    
      HBase集群搭建:
        https://www.cnblogs.com/yinzhengjie2020/p/12239031.html

    4>.HBase在商业项目中的能力

      每天:
        (1)消息量:发送和接收的消息数超过60亿
        (2)将近1000亿条数据的读写
        (3)高峰期每秒150万左右操作
        (4)整体读取数据占有约55%,写入占有45%
        (5)超过2PB的数据,涉及冗余共6PB数据
        (6)数据每月大概增长300千兆字节。

    5>.HBase2.0新特性

      2017年8月22日凌晨2点左右,HBase发布了2.0.0 alpha-2,相比于上一个版本,修复了500个补丁,我们来了解一下2.0版本的HBase新特性。
    
      最新文档:     http:
    //hbase.apache.org/book.html#ttl

    二.HBase数据结构

    1>.RowKey

      与nosql数据库们一样,RowKey是用来检索记录的主键。访问HBASE table中的行,只有三种方式:
        (1)通过单个RowKey访问(get)
        (2)通过RowKey的range(正则)(like)
        (3)全表扫描(scan)
    
      RowKey行键 (RowKey)可以是任意字符串(最大长度是64KB,实际应用中长度一般为
    10-100bytes),在HBASE内部,RowKey保存为字节数组。

      存储时,数据按照RowKey的字典序(byte order)排序存储(换句话说,就是按照ASCII表的顺序进行排序)。设计RowKey时,要充分排序存储这个特性,将经常一起读取的行存储放到一起(位置相关性,有点类似于HDD的预读技术)。

      为什么RowKey保存为字节数组,而不保存为字符串呢?
        答:为了方便压缩"RowKey",从而更好的利用内存空间。
        举个例子:
          假设RowKey为"a1a2a3",如果以字符串保存的话会占用6个字节,而使用字节数组对应[97,49,97,50,97,51]。
          看到这里估计很多小伙伴已经想原因了,我们知道一个字节的范围是[-128~127],很明显使用字节数组保存RowKey为"a1a2a3"要比使用字符串保存更节省bit,根本原因是更适合压缩(比如记录字符"a"出现的次数,"a:[0,2,4]")。

    2>.Column Family

      HBASE表中的每个列,都归属于某个列族(Column Family)。

      列族是表的schema的一部分(而列不是),必须在使用表之前定义。

      列名都以列族作为前缀。例如"student"表中的"courses:history","courses:math"都属于courses这个列族。

    3>.Cell

      HBase由{rowkey, column Family:columu, version} 来唯一确定的单元称之为"cell"。

      cell中的数据是没有类型的,全部是字节码形式存贮。

    4>.TimeStamp

      每个cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是64位整型。时间戳可以由HBASE(在数据写入时自动)赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。
    
      如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
    
      为了避免数据存在过多版本造成的的管理(包括存贮和索引)负担,HBASE提供了两种数据版本回收方式(用户可以针对每个列族进行设置):
        (1)保存数据的最后n个版本;
        (2)保存最近一段时间内的版本(比如最近七天)。

    5>.命名空间结构

      Tables:
        所有的表都是命名空间的成员,即表必属于某个命名空间,如果没有指定,则在default默认的命名空间中。
      RegionServer group:
        一个命名空间包含了默认的RegionServer Group。
      Permission:
        权限,命名空间能够让我们来定义访问控制列表ACL(Access Control List)。例如,创建表,读取表,删除,更新等等操作。
      Quota:
        限额,可以强制一个命名空间可包含的region的数量。

    三.HBase写入流程剖析

     

        如上图所示,Client想要写入"teacher,10001",此时HBase的写入流程大致如下所示:
        (1)Client发起第一次请求先访问zookeeper(/hbase/meta-region-server)获取元数据信息表;
        (2)Zookeeper返回Client元数据表所在的RegionServer(rs101:16020);
        (3)Client发起第二次请求访问RegionServer(rs101:16020)查询待写入列族数据在元数据表中的信息;
        (4)根据namespace、表名和rowkey在meta表中找到对应的region信息并返回给Client;
        (5)Cleint找到这个region对应的regionserver并发起第三次请求向HregionServer(rs106:16020)发送写请求;
        (6)regionserver找到查找对应的region;
        (7)HRegionServer先将数据写到HLog(write ahead log),目的为了防止数据丢失;
        (8)HRegionServer在将数据写到内存(MemStore);
        (9)最后反馈Client写成功;
    
      由于MemStore的数据是存放在内存中的,因此不能持续存放数据,其flush过程如下:
        (1)当MemStore数据达到阈值(默认是128M,老版本是64M,该默认值参考了HDFS的Block默认值),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据;
        (2)并将数据存储到HDFS中;
        (3)在HLog中做标记点。
    
      温馨提示:
        当数据成功写入到Region的Hlog后,会再将数据写入到MemStore,当MemStore写不进去(该区域内存已满),此时会做回滚(RockBack)操作,即将成功写入HLog的数据的数据删除掉,并返回给客户端写入失败,其目的是保证数据的一致性。
        需要注意的,HBase并不支持事务。

    四.HBase读取流程剖析

      如上图所示,Client想要读取"teacher,10001",此时HBase的读取流程大致如下所示:
        (1)Client发起第一次请求先访问zookeeper(/hbase/meta-region-server)获取元数据信息表;
        (2)Zookeeper返回Client元数据表所在的RegionServer(rs101:16020);
        (3)Client发起第二次请求访问RegionServer(rs101:16020)获取"teacher,10001"在元数据(meta)表中的信息;
        (4)根据namespace、表名和rowkey在meta表中找到对应的region信息并返回给Client;
        (5)Cleint找到这个region对应的regionserver(rs106:16020)并发起第三次请求访问"teacher,10001"数据;
        (6)regionserver找到查找对应的region;
        (7)先从MemStore(写缓存,还没有写入到HFile)找数据;
        (8)如果MemStore没有找到数据,再到BlockCache(读缓存)里面找数据;
        (9)BlockCache也没有找到数据,再到StoreFile(HFile)上读(为了读取的效率);
        (10)如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache;
        (11)将查询结果返回给客户端;
              
      温馨提示:    
        综上所述,HBase查询效率流程比较复杂,因此查询效率并不高。我们不应该用HBase来做即席查询,而用它来做统计分析。如果你非要用作查询操作的话请考虑使用MySQL。

    五.HBase数据合并过程剖析

      我们知道当MemStore数据达到阈值是会将数据flush到磁盘,但有的时候不一定要达到阈值时才会溢写到磁盘,比如当服务器的Region数量过多时,此时MemStroe数量也会增多,单台服务器的资源是有限的,因此未必是每个MemStore都达到128MB才会写入。
    
      举个例子:
        一个HRegionServer内存为1GB,其有100个Region,即每个MemStore很有可能在10MB左右就开始溢写到磁盘,这样就会导致HDFS集群存在大量小文件。而HDFS存储大量小文件无疑是浪费集群资源,因此HBase需要对其进行优化,将大量的小文件进行合并。
     
      数据合并过程
        (1)当数据块达到3块,Hmaster触发合并操作,Region将数据块加载到本地,进行合并;
        (2)当合并的数据超过256M,进行拆分,将拆分后的Region分配给不同的HRegionServer管理(由HMaster负责调度分配);
        (3)当HregionServer宕机后(数据并没有丢失,因为数据存储在HDFS集群),将HRegionServer上的HLog拆分,然后分配给不同的HRegionServer加载,修改".META.";
        (4)注意:HLog会同步到HDFS。
    
      温馨提示:
        在HBase 1.3.1版本中存在以下一行源码:
          Math.min(getDesiredMaxFileSize(),initialSize * tableRegionsCount * tableRegionsCount * tableregionsCount)
        各变量解释如下:
          getDesiredMaxFileSize:
            对应常量"hbase.hregion.max.filesize",该常量默认是10G
          initialSize:
            默认是常量"hbase.hregion.memstore.flush.size"(默认128MB)的2倍,即256MB.
          tableRegionsCount:
            一个未被预分区的表默认Region数量是1。
        结论:
          当一个未被预分区的Region数量为1时,当第一次合并的数据块超过256MB时会被切分,而第二次合并的数据块就不是256MB啦,原因很简单,因为在第一次切分后tableRegionsCount的数量变为2。
          以此类推:
            第二次切分的大小应该为:
    "256 * 2 * 2 * 2" = 2048MB(2G),该值小于10G,因此第二次切分大小应该为2G
            第三次切分的大小应该为:"256 * 3 * 3 * 3" = 6912MB(约为7G),该值小于10G,因此第三次切分大小应该为6912MB
            第四次切分的大小应该为:"256 * 4 * 4 * 4" = 16384MB(16G),该值大于10G,因此第四次切分大小应该为10G

    六.HBase删除流程剖析

      HBase无论时修改还是删除,其实本质上并没有删除,而是增加了一些标记,比如"type=Delete"之类的。如下图所示,删除字段时看似被删除但实际并没有被立刻删除,而是被标记删除啦。

      HBase会在集群空闲的时间删除它。当然在HBase重量级合并HBase上的小文件时,也会顺便将标记删除的数据删除后在合并。
    hbase(main):105:0> scan 'teacher',{STARTROW =>'10001',STOPROW => '10001',VERSIONS => 5}
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417809578, value=yinzhengjie2015                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417803412, value=yinzhengjie2017                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417762124, value=yinzhengjie2018                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417698039, value=yinzhengjie2019                                                                                                                                     
    1 row(s)
    Took 0.0110 seconds                                                                                                                                                                                                                                                           
    hbase(main):106:0> scan 'teacher',{STARTROW =>'10001',STOPROW => '10001'}
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417809578, value=yinzhengjie2015                                                                                                                                     
    1 row(s)
    Took 0.0057 seconds                                                                                                                                                                                                                                                           
    hbase(main):107:0> delete 'teacher','10001','synopsis:name'
    Took 0.0662 seconds                                                                                                                                                                                                                                                           
    hbase(main):108:0> 
    hbase(main):108:0> scan 'teacher',{STARTROW =>'10001',STOPROW => '10001'}
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
    1 row(s)
    Took 0.0147 seconds                                                                                                                                                                                                                                                           
    hbase(main):109:0> scan 'teacher',{STARTROW =>'10001',STOPROW => '10001',VERSIONS => 5}
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417803412, value=yinzhengjie2017                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417762124, value=yinzhengjie2018                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417698039, value=yinzhengjie2019                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590413634375, value=yinzhengjie                                                                                                                                         
    1 row(s)
    Took 0.0089 seconds                                                                                                                                                                                                                                                           
    hbase(main):110:0> 
    hbase(main):107:0> delete 'teacher','10001','synopsis:name'
    hbase(main):111:0> scan 'teacher'
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
     10002                                                               column=synopsis:address, timestamp=1590413659636, value=shijiazhuang                                                                                                                                     
     10002                                                               column=synopsis:age, timestamp=1590413654294, value=27                                                                                                                                                   
     10002                                                               column=synopsis:name, timestamp=1590413648325, value=jason yin                                                                                                                                           
    2 row(s)
    Took 0.0066 seconds                                                                                                                                                                                                                                                           
    hbase(main):112:0> delete 'teacher','10002','synopsis:name'
    Took 0.0087 seconds                                                                                                                                                                                                                                                           
    hbase(main):113:0> scan 'teacher'
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
     10002                                                               column=synopsis:address, timestamp=1590413659636, value=shijiazhuang                                                                                                                                     
     10002                                                               column=synopsis:age, timestamp=1590413654294, value=27                                                                                                                                                   
    2 row(s)
    Took 0.0061 seconds                                                                                                                                                                                                                                                           
    hbase(main):114:0> scan 'teacher',{RAW => true,VERSIONS => 5}
    ROW                                                                  COLUMN+CELL                                                                                                                                                                                              
     10001                                                               column=synopsis:address, timestamp=1590413642872, value=beijing                                                                                                                                          
     10001                                                               column=synopsis:name, timestamp=1590417809578, type=Delete                                                                                                                                               
     10001                                                               column=synopsis:name, timestamp=1590417809578, value=yinzhengjie2015                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417806829, value=yinzhengjie2016                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417803412, value=yinzhengjie2017                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417762124, value=yinzhengjie2018                                                                                                                                     
     10001                                                               column=synopsis:name, timestamp=1590417698039, value=yinzhengjie2019                                                                                                                                     
     10002                                                               column=synopsis:address, timestamp=1590413659636, value=shijiazhuang                                                                                                                                     
     10002                                                               column=synopsis:age, timestamp=1590413654294, value=27                                                                                                                                                   
     10002                                                               column=synopsis:name, timestamp=1590413648325, type=Delete                                                                                                                                               
     10002                                                               column=synopsis:name, timestamp=1590413648325, value=jason yin                                                                                                                                           
    2 row(s)
    Took 0.0162 seconds                                                                                                                                                                                                                                                           
    hbase(main):115:0> 
    hbase(main):112:0> delete 'teacher','10002','synopsis:name'

     

    七.博主推荐阅读

      HBase shell常用命令总结
        https://www.cnblogs.com/yinzhengjie2020/p/12239339.html
    
      HBase完全分布式集群搭建:
        https://www.cnblogs.com/yinzhengjie2020/p/12239031.html
    
      HBase API实战案例:
        https://www.cnblogs.com/yinzhengjie2020/p/12271220.html
  • 相关阅读:
    P3811乘法逆元
    P4549裴蜀定理
    备用代码区
    其他板子整理
    DP
    图论板子整理
    约数
    浅谈假学习假努力
    质数
    P1019 单词接龙
  • 原文地址:https://www.cnblogs.com/yinzhengjie2020/p/12237264.html
Copyright © 2020-2023  润新知