HBase架构及读写流程

 

HBase架构:

 

 

Client
    访问HBase的接口并维护cache来加快对HBase的访问


Zookeeper
    ​ 1、保证任何时候,集群中只有一个活跃master
    ​ 2、存储所有region的寻址入口
    ​ 3、实时监控region server的上线和下线信息,并实时通知master
    ​ 4、存储HBase的schema和table元数据

注:zookeeper存储表的元数据地址,client请求查询表拿到表的地址后再访问对应表


Master
    ​ 1、为region server分配region
    ​ 2、负责region server的负载均衡
    ​ 3、发现失效的region server并重新分配失效的region
    ​ 4、管理用户对table的增删改操作

RegionServer
    ​ 1、region server维护region,处理对这些region的IO请求
    ​ 2、region server负责切分在运行过程中变得过大的region

    region
    ​ 1、HBase自动把表水平划分成多个区域(region),每个region会保存一个表里某段连续的数据
    ​ 2、每个表一开始只有一个region,随着数据不断插入表,region不断增大,当增大到一个阈值的时候,region就会等分会两个region
    ​ 3、当table中的行不断增多,就会有越来越多的region。这样一张完整的表被保存在多个Regionserver 上
    
    memstore与storefile
    ​ 1、一个region由多个store组成,一个store对应一个CF(列族)
    ​ 2、store包括位于内存中的memstore和位于磁盘的storefile写操作先写入memstore,当memstore中的数据达到某个阈值(默认64m),
        regionserver会启动flashcache进程写入storefile,每次写入形成单独的一个storefile
    ​ 3、当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、major ),在合并过程中会进行版本合并和删除工作(majar),形成更大的storefile
    ​ 4、当一个region所有storefile的大小和数量超过一定阈值后,会把当前的region分割为两个,并由hmaster分配到相应的regionserver,实现负载均衡
    ​ 5、客户端检索数据,先在memstore找,找不到再去blockcache查找,找不到再找storefile,即:client->memstore->blockcache->hfile
    
    注:​

  1、Region是HBase中存储和负载均衡的最小单元,不同的Region可以分布在不同的 Region Server上
  2、Region由一个或者多个Store组成,每个store保存一个columns family
  3、每个Strore又由一个memStore和0至多个StoreFile组成
  4,memstore为写入缓存,blockcache读取缓存
  5,Hbase内部为主从集群模式,hmaster主节点regionServer为从节点,master负责增删改管理regisonServer

  6,HBase中更新操作并没有更新原数据,而是使用时间戳属性实现了多版本,删除操作也并没有真正删除原数据,只是插入了一条打上”deleted”标签的数据,而真正的数据删除发生在系统异步执行Major_Compact的时候

 

三层scanner:RegionScanner、StoreScanner以及StoreFileScanner,三者是层级的关系

 

 

  HBase数据结构:

  rowkey:每行记录的唯一标识,按照字典序排序,只能存储64K的数据
  Column Family:表中的每个列都归属于某个列族,列名以列族作为前缀,新的列族成员(列)可以动态添加,权限控制、存储以及调优都是在列族层面进行,同一列族里面的数据存储在同一目录下,由几个文件保存
  Cell:cell中的数据是没有类型内容是未解析的字节数组,带有timestamp版本号的
  TimeStamp:每个cell存储单元对同一份数据有多个版本,时间戳区分每个版本之间的差异,不同版本的数据按照时间倒序排序,时间戳可以由HBase(在数据写入时自动)赋值,此时间戳是精确到毫秒的当前系统时间

 

HBase读写流程

    读流程:
    ​ 1、客户端从zookeeper中获取meta表所在的regionserver节点信息
    ​ 2、客户端访问meta表所在的regionserver节点,获取到region所在的regionserver信息
    ​ 3、客户端访问具体的region所在的regionserver,找到对应的region及store
    ​ 4、首先从memstore中读取数据,如果读取到了那么直接将数据返回,如果没有,则去blockcache读取数据
    ​ 5、如果blockcache中读取到数据,则直接返回数据给客户端,如果读取不到,则遍历storefile文件,查找数据
    ​ 6、如果从storefile中读取不到数据,则返回客户端为空,如果读取到数据,那么需要将数据先缓存到blockcache中(方便下一次读取),然后再将数据返回给客户端
    ​ 7、blockcache是内存空间,如果缓存的数据比较多,满了之后会采用LRU策略,将比较老的数据进行删除

注:如何保证client读取blockcache内为新数据?cache与HFile共同维护一索引表,索引表内指向最新版本数据源,当client读取指定rowkey数据时会访问索引,索引给出给出最新版本数据,如blockcache不是最新的,那本次会读取hfile并更新blockcache数据,从而使client访问最新数据
    
    
    写流程:
     1、客户端从zookeeper中获取meta表所在的regionserver节点信息
    ​ 2、客户端访问meta表所在的regionserver节点,获取到region所在的regionserver信息
    ​ 3、客户端访问具体的region所在的regionserver,找到对应的region及store
    ​ 4、开始写数据,写数据的时候会先向hlog中写数据(方便memstore中数据丢失后能够根据hlog恢复数据,向hlog中写数据的时候也是优先写入内存,后台会有一个线程定期异步刷写数据到hdfs,如果hlog的数据也写入失败,那么数据就会发生丢失)
    ​ 5、hlog写数据完成之后,在将数据写入到memstore,memstore默认大小是64M,当memstore满了之后会进行统一的溢写操作,将memstore中的数据持久化到hdfs中,
    ​ 6、频繁的溢写会导致产生很多的小文件,因此会进行文件的合并,文件在合并的时候有两种方式,minor和major,   minor表示小范围文件的合并,major表示将所有的storefile文件都合并成一个

 

 Hbase key-value结构:

 

 数据查找过程:

对于一行数据的查询,又可以分解为多个列族的查询,首先查询列族1上该行的数据集合,再查询列族2里该行的数据集合
检查该KeyValue的KeyType是否是Deleted/DeletedCol等,如果是就直接忽略该列所有其他版本,跳到下列(列族)
检查该KeyValue的Timestamp是否在用户设定的Timestamp Range范围,如果不在该范围,忽略
检查该KeyValue是否满足用户设置的各种filter过滤器,如果不满足,忽略
检查该KeyValue是否满足用户查询中设定的版本数,比如用户只查询最新版本,则忽略该cell的其他版本;

 

 

hbase调优:

 1,Pre-Creat Regions:通过预先创建一些空的regions可以加快批量写入速度,这样当大量写入请求到HBase时,会按照region分区情况,在集群内做数据的负载均衡

 2,row key design:rowkey可以是任意字符串,最大长度64KB存为byte[]字节数组。

     (1)rowkey尽可能短,<100byte 如果rowkey过长会影响HFile的存储效率以及检索效率
     (2)散列原则--实现负载均衡,这样将提高数据均衡分布在每个Regionserver实现负载均衡的几率。如果没有散列字段,可能产生所有新数据都在
     一个 RegionServer上堆积的热点现象,这样在做数据检索的时候负载将会集中在个别RegionServer,降低查询效率。
     (3)range data,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块

 3,low colum family:目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,其邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O    

    (1)每个列族对应一个memstore,当包含多列族的时候对应多个memstore,一个memstore在flush时对应一个hfile,因此会产生很多hfile文件。flush操作是region级别,当region中某个memstore被flush的时,同一个region的其他memstore也会进行flush操作,如列族之间的数据分布不均匀时,会产生更多的磁盘文件。多个列族之间的数据量相差很大时候,region的split操作会导致原本数据量小的文件被进一步的拆分,而产生更多的小文件。

    (2)HDFS 一个目录下的文件数有限制的(dfs.namenode.fs-limits.max-directory-items),如果有 N 个列族,M 个 Region,那持久化到 HDFS 至少会产生 NM 个文件,而每个列族对应底层的 HFile 为 K 个,那么最终表在 HDFS 目录下的文件数将是 N*M*K,可能超出限制导致写入失败

 4,Max Version:设置表中数据的最大版本,如果只需要保存最新版本的数据,那么可以设置setMaxVersions(1),保留更多的版本信息会占用更多的存储空间

 5,Time to Live:设置表中数据的存储生命期,过期数据将自动被删除,适用于临时数据存储

 6,Compaction设置:
  当MemStore累计到一定阈值时,就会创建一个新的MemStore,并且将老的MemStore添加到flush队列,由单独的线程flush到磁盘上,成为一个StoreFile。
  为了防止小文件(被刷到磁盘的menstore)过多,以保证保证查询效率,hbase需要在必要的时候将这些小的store file
  合并成相对较大的store file,这个过程就称之为compaction。compaction:minor compaction和major compaction。

  (1)minor compaction:
       hbase.hstore.compaction.min :默认值为 3,表示至少需要三个store file时,minor compaction才会启动
​       hbase.hstore.compaction.max 默认值为10,表示一次minor compaction中最多10个store file
​       hbase.hstore.compaction.min.size 文件大小小于该值的store file 一定会加入到minor compaction的store file中
​       hbase.hstore.compaction.max.size 文件大小大于该值的store file 一定不会被添加到minor compaction
      //执行minor对上面的参数综合判断使用
   hbase.hstore.compaction.ratio :将 StoreFile 按文件年龄排序,minor compaction 总是从 older store file 开始,如果该文件的 size 小于后面
      hbase.hstore.compaction.max 个 store file size 之和乘以 ratio 的值,那么该 store file 将加入到 minor compaction 中。
      如果满足 minor compaction 条件的文件数量大于 hbase.hstore.compaction.min才会启动

 (2)major compaction:

     触发major compaction的可能条件,major_compact命令,region server自动运行
       hbase.hregion.majorcompaction 默认为24 小时
       hbase.hregion.majorcompaction.jetter 默认值为0.2,对参数hbase.hregion.majorcompaction 规定的值起到浮动的作用,
       假如两个参数都为默认值24和0,2,那么major compact最终使用的数值为:19.2~28.8 这个范围

  写入优化:
  是否需要写WAL:不特别关心异常情况下部分数据的丢失,而更关心数据写入吞吐量情况(关闭WAL写入,写入吞吐量可以提升2x~3x。WAL异步写入带来1x~2x的性能提升)
  put批量提交:使用批量put接口可以减少客户端到RegionServer之间的RPC连接数
  请求均衡分配:如果不均衡,一方面会导致系统并发度较低,另一方面也有可能造成部分节点负载很高,进而影响其他业务(RowKey设计以及预分区策略)
  KeyValue数据过大:随着单行数据大小不断变大,写入吞吐量急剧下降,写入延迟在100K之后急剧增大

 

 

  读取优化:
  scan缓存设置:client发起一次scan请求,实际并不会一次就将所有数据加载到本地,而是分成多次RPC请求进行加载。(1)大量数据请求可能会导致网络带宽严重消耗进而影响其他业务,(2)也有可能因为数据量太大导致client发生OOM
   首先加载一部分数据到本地,然后遍历处理,再加载下一部分数据到本地处理,如此往复,直至所有数据都加载完成,默认100条数据。在一些大scan(一次scan可能需要查询几万甚至几十万行数据)来说,每次请求100条数据意味着一次scan

   需要几百甚至几千次RPC请求以考虑将scan缓存设置增大,比如设为500或者1000就可能更加合适
  get使用批量请求:减少client到RegionServer之间的RPC连接次数
  设置禁止缓存:通常离线批量读取数据会进行一次性全表扫描,一方面数据量很大,另一方面请求只会执行一次,可考虑停用缓存scan.setBlockCache(false)
  Compaction消耗系统资源过多:正常配置情况下Minor Compaction并不会带来很大的系统资源消耗,除非因为配置不合理导致Minor Compaction太过频繁,或者Region设置太大情况下发生Major Compaction,观察系统IO资源以及带宽资源使用情况,
   再观察Compaction队列长度,确认是否由于Compaction导致系统资源消耗过多。通常不建议开启自动Major Compaction,手动低峰期触发

 

posted @ 2019-08-24 18:10  HappyCode002  阅读(840)  评论(0编辑  收藏  举报