HBase集群优化篇

              HBase集群优化篇

                                 作者:尹正杰

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

一.HBase的高可用实战案例

  博主推荐阅读:
    https://www.cnblogs.com/yinzhengjie2020/p/12274860.html

 

二.HBase预分区

  博主推荐阅读:
    https://www.cnblogs.com/yinzhengjie2020/p/12914075.html

三.rowkey设计原则

  一条数据的唯一标识就是rowkey,那么这条数据存储于哪个分区,取决于rowkey处于哪个一个预分区的区间内,设计rowkey的主要目的 ,就是让数据均匀的分布于所有的region中,在一定程度上防止数据倾斜。

  接下来我们就谈一谈rowkey的设计原则及常用的设计方案。

1>.rowkey的三大设计原则

  (1)唯一性原则:
    这个很好理解,RowKey的角色类似于关系型数据库当中的主键,因此Rowkey不能重复。
    举个例子,使用用户姓名作为RowKey就很不适合,究其原因是因为姓名太容易重复了,如果非要用姓名作为RowKey就得考虑加一些后缀来做区分。  
    rowkey在设计上保证其唯一性。rowkey是按照字典顺序排序存储的,因此,设计rowkey的时候,要充分利用这个排序的特点,将经常读取的数据存储到一块,将最近可能会被访问的数据放到一块。
  (
2)长度原则:     而设计太长会导致占用更多的存储空间影响查询效率,设计的太短对业务要求查询也不是特方便。因此在能满足查询条件的情况下,RowKey设计的越短越好。     虽然RowKey最大长度是64KB,实际应用中长度一般为10-100bytes。以byte[] 形式保存,一般设计成定长。
    建议越短越好,不要超过16个字节,原因如下:
      (a)数据的持久化文件HFile中是按照KeyValue存储的,如果rowkey过长,比如超过100字节,1000w行数据,光rowkey就要占用100*1000w=10亿个字节,将近1G数据,这样会极大影响HFile的存储效率;
      (b)MemStore将缓存部分数据到内存,如果rowkey字段过长,内存的有效利用率就会降低,系统不能缓存更多的数据,这样会降低检索效率。
      (c)目前操作系统都是64位系统,内存8字节对齐,控制在16个字节,8字节的整数倍利用了操作系统的最佳特性。        (
3)散列原则:     让RowKey没有规律,可以实现均匀分配。     如果rowkey按照时间戳的方式递增,不要将时间放在二进制码的前面,建议将rowkey的高位作为散列字段,由程序随机生成,低位放时间字段,这样将提高数据均衡分布在每个RegionServer,以实现负载均衡的几率。
    如果没有散列字段,首字段直接是时间信息,所有的数据都会集中在一个RegionServer上,这样在数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,会降低查询效率.     常见的散列手段如下:
      (a)加盐:
        这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。
        分配的前缀种类数量应该和你想使用数据分散到不同的region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点.       (b)哈希:
        哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据。       (c)反转:
        第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
        反转rowkey的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题。       (d)时间戳反转:
        一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey的一部分对这个问题十分有用,可以用Long.Max_Value
- timestamp追加到key的末尾。
        例如[key][reverse_timestamp] ,[key]的最新值可以通过scan [key]获得[key]的第一条记录,因为HBase中rowkey是有序的,第一条记录是最后录入的数据。比如需要保存一个用户的操作记录,按照操作时间倒序排序,在设计rowkey的时候,可以这样设计[userId反转][Long.Max_Value - timestamp],在查询用户的所有操作记录数据的时候,直接指定反转后的userId,startRow是[userId反转][000000000000],stopRow是[userId反转][Long.Max_Value - timestamp]如果需要查询某段时间的操作记录,startRow是[user反转][Long.Max_Value - 起始时间],stopRow是[userId反转][Long.Max_Value - 结束时间]

2>.生成随机数,hash,散列值

  举个例子:
    原本rowKey为1001的,SHA1后变成:dd01903921ea24941c26a48f2cec24e0bb0e8cc7
    原本rowKey为3001的,SHA1后变成:49042c54de64a1e9bf0b33e00245660ef92dc7bd
    原本rowKey为5001的,SHA1后变成:7b61dec07e02c188790670af43e717f0f46e8913

  在做此操作之前,一般我们会选择从数据集中抽取样本,来决定什么样的rowKey来Hash后作为每个分区的临界值。

3>.字符串反转

  假设有以下3个订单编号:
    20200531000001
    20200531000002
    20200531000003
  反转后:
    10000013500202
    20000013500202
    30000013500202

  如果按照上面的字符串作为RowKey则很有可能这3个订单被写入到同一个Region中,但是如果我们做一个反转操作后,很可能这3条订单数据被写入到3个不同的Region中。

4>.字符串拼接

  举个例子:
    20200531000001_a1b2c3
    20200531000001_abcdef

四.内存优化

  HBase操作过程中需要大量的内存开销,毕竟Table是可以缓存在内存中的,一般会分配整个可用内存的70%给HBase的Java堆。

  但是不建议分配非常大的堆内存,因为GC过程持续太久会导致RegionServer处于长期不可用状态,一般16~48G内存就可以了,如果因为框架占用内存过高导致系统内存不足,框架一样会被系统服务拖死。

  博主推荐阅读:
    https://www.cnblogs.com/yinzhengjie/tag/JVM/

五.HBase配置基础优化

1>.允许在HDFS的文件中追加内容

  配置文件:
    hdfs-site.xml、hbase-site.xml
  相关参数:
    dfs.support.append
  参数说明:
    开启HDFS追加同步,可以优秀的配合HBase的数据同步和持久化。默认值为true。

2>.优化DataNode允许的最大文件打开数

  配置文件:
    hdfs-site.xml
  相关参数:
    dfs.datanode.max.transfer.threads
  参数说明:
    HBase一般都会同一时间操作大量的文件,根据集群的数量和规模以及数据动作,设置为8192或者更高。默认值:
4096。

3>.优化延迟高的数据操作的等待时间

  配置文件:
    hdfs-site.xml
  相关参数:
    dfs.image.transfer.timeout
  参数说明:
    如果对于某一次数据操作来讲,延迟非常高,socket需要等待更长的时间,建议把该值设置为更大的值(默认60000毫秒),以确保socket不会被timeout掉。

4>.优化数据的写入效率

  配置文件:
    mapred-site.xml
  相关参数:     mapreduce.map.output.compress     mapreduce.map.output.compress.codec
  参数说明:
    开启这两个数据可以大大提高文件的写入效率,减少写入时间。第一个属性值修改为true,第二个属性值修改为:org.apache.hadoop.io.compress.GzipCodec或者其他压缩方式。

5>.设置RPC监听数量

  配置文件:
    hbase-site.xml
  相关参数:
    hbase.regionserver.handler.count
  参数说明:
    默认值为30,用于指定RPC监听的数量,可以根据客户端的请求数进行调整,读写请求较多时,增加此值。

6>.优化HStore文件大小

  配置文件:
    hbase-site.xml
  
  相关参数:
    hbase.hregion.max.filesize
  参数说明:
    默认值10737418240(10GB),如果需要运行HBase的MR任务,可以减小此值,因为一个region对应一个map任务,如果单个region过大,会导致map任务执行时间过长。
    该值的意思就是,如果HFile的大小达到这个数值,则这个region会被切分为两个Hfile。

7>.优化hbase客户端缓存

  配置文件:
    hbase-site.xml   
  相关参数:
    hbase.client.write.buffer
  参数说明:
    用于指定HBase客户端缓存,增大该值可以减少RPC调用次数,但是会消耗更多内存。一般我们需要设定一定的缓存大小,以达到减少RPC次数的目的。

8>.指定scan.next扫描HBase所获取的行数

  配置文件:
    hbase-site.xml

  相关参数:     hbase.client.scanner.caching
  参数说明:     用于指定scan.next方法获取的默认行数,值越大,消耗内存越大。

9>.协处理器(coprocessor)配置

  配置文件:
    hbase-site.xml

  相关参数:
    hbase.coprocessor.abortonerror

  参数说明:
    如果设置为true,则当协处理器加载失败、初始化失败或抛出意外的可丢弃对象时,将导致宿主服务器(主服务器或区域服务器)中止。
    将此设置为false将允许服务器继续执行,但相关协处理器的系统范围状态将变得不一致,因为它将仅在服务器的子集中正确执行,因此这对于仅调试非常有用。
    生产环境建议设置成false以增强HRegionServer的可用性。

10>.Flush、Compact、Split机制

Flush机制:
    当MemStore达到阈值,将Memstore中的数据Flush进Storefile,128M就是Memstore的默认阈值。
    
  Compact机制:
    compact机制则是把Flush出来的小文件合并成大的Storefile文件。

  Spilt机制:
    split则是当Region达到阈值,会把过大的Region一分为二。

  相关参数说明:
    hbase.hregion.memstore.flush.size:134217728
      这个参数的作用是当单个HRegion内所有的Memstore大小总和超过指定值时,flush该HRegion的所有memstore。RegionServer的flush是通过将请求添加一个队列,模拟生产消费模型来异步处理的。
      那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM。
    hbase.regionserver.global.memstore.upperLimit:0.4
    hbase.regionserver.global.memstore.lowerLimit:0.38
      当MemStore使用内存总量达到hbase.regionserver.global.memstore.upperLimit指定值时,将会有多个MemStores flush到文件中;
      MemStore flush 顺序是按照大小降序执行的,直到刷新到MemStore使用内存略小于hbase.regionserver.global.memstore.lowerLimit(该值默认值大小是"hbase.regionserver.global.memstore.upperLimit"的95%)。
    hbase.regionserver.optionalcacheflushinterval:3600000
      内存中的文件在自动刷新之前能够存活的最长时间,默认是1H.
    hbase.regionserver.region.split.policy:org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy
      region在切分的时候的默认切分策略,不同版本的切分策略是不一样的,org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy是1.3.1版本的默认切分策略。
    hbase.regionserver.regionSplitLimit:1000
      当某个HRegionServer上的region到达这个限制时,不会在进行region切分,也就是一个HRegionServer默认最大允许有1000个region。
    hbase.hregion.memstore.block.multiplier:4    
      当一个HRegion上的memstore的大小满足hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size, 这个HRegion会执行flush操作并阻塞对该HRegion的写入。
    hbase.hregion.majorcompaction:604800000  
      一个region进行 major compaction合并的周期,在这个点的时候, 这个region下的所有hfile会进行合并,默认是7天,major compaction非常耗资源,建议生产关闭(设置为0),在应用空闲时间手动触发。
    hbase.hstore.compaction.max:
      每个minor compaction操作的 允许的最大hfile文件上限。
原文地址:https://www.cnblogs.com/yinzhengjie2020/p/12275462.html