什么导致HBase性能下降?

  • jvm内存分配和GC回收策略
  • 与HBase运行机制相关配置不合理 (hbase-site.xml配置优化)
  • 表结构设计不合理以及用户使用方式不合理

HBase数据存储过程

  • HBase写入的时候会先写入memstore达到一定大小,会flush到磁盘保存成HFile,当HFile小文件太多会执行compact操作进行合并。对HBase来说,当每一个store,仅仅包含一个文件的时候 查询效率才是最高的,因为如果小文件太多了,查询的时候需要的寻址时间就越长,因此HBase会合并小文件,从而减少磁盘寻道时间,从而提高读取速度,这个过程就成为compact。但是执行compact器间,可能会阻塞数据的写入和读取,那么合适执行compact是一个复杂的操作,compat的时候选择哪些文件,选择哪些合适线程池才能达到最大的性能,是一个很重要的决策。
  • 如果region太大,会将region进行split,分配到不同的region进行管理。这里其实也是非常耗费性能的操作,可能会造成当前的region不能读取,也不能写入。
split概念
  • split:将一个region,且分为两个region
compact概念
  • minor compaction:
    选取一些小的相邻的storefile将他们合并成一个更大的storefile。
  • major compaction:
    所有的storefile合并成一个storefile,清理无意义的数据
    (1)被删除的数据(被删除的数据只是被标记删除,并没有真正的删除)。
    (2)TTL过期的数据。
    (3) 版本号超过设定版本号的数据。

HBase Compact检查

  • 当MemStore 被flush到磁盘
  • 用户执行shell命令compact,major_compact或者调用相应的API
  • HBase后台线程周期性触发检查

HBase 优化


常用服务端配置优化

  • jvm设置与GC设置
    可以适当增加regionserver内存,regionserver内存设置大一些, 可以有效避免full gc,
    并且对block cache 支持也会好一点。
  • hbase-site.xml部分属性配置

HBase properties

简介

hbase.regionserver.handler.count

rpc请求的线程数量,默认值是10,提升handler大小,可以有效提升regionserver接收请求的能力,但是也不是越大越好,取决于硬件性能

hbase.hregion.max.filesize

当region的大小大于设定值后hbase就开始split,默认大小是10G, 可以根据存储的内容,合理配置,建议手动进行split操作

hbase.hregion.majorcompaction

major compaction的执行周期,默认为1天,建议设置为0,禁止major compaction,生产环境中,进行major compaction可能会执行一天之久,可以在业务低峰的时候,进行手动合并,或者通过脚本,定期执行合并操作。

hbase.hstore.compaction.min

任何一个store,里面的storefile超过该值,会触发默认的合并操作,默认值是3

hbase.hstore.compaction.max

一次最多合并多少个storefile,如果storefile比较大, 应该把这个值,设置小一点,避免内存溢出

hbase.hstore.blockingStoreFiles

一个region中的store内有超过XXX个storefile时候,则block所有的写请求进行compaction

hbase.hregion.memstore.flush.size

memstore 超过该值会被flush,根据内存大小,可以适当调整大一点

hbase.hregion.memstore.block.multiplier

如果memstore内存大小超过flush.size*multiplier,会阻塞该memstore的写操作,建议将这个值设置为5,如果设置太大,可能会出现内存溢出

hbase.block.cache.size

regionserver的block cache的内存大小限制,在偏向读的业务中可以适当调大一些

一般我们会手动执行split和compact,以降低这些操作可能对正常业务造成的不必要的影响,我们也可以开发脚本,来在业务低峰,定时执行split和compact 操作。


常用优化策略(以实际需求为主)

  • 预先分区
    HBase在建表的时候,默认在一个regionserver自动建立一个region,当region太大的时候,会执行split操作,将一个region split 成两个region,并发送到不同的regionserver进行维护 以实现负载均衡,但是split又是一个比较耗时的操作。
    创建HBase表的时候预先创建一些空的Regions,并指定Region的存储范围,这样数据会被写入到指定的region里面,我们可以减少很多的IO操作,通过预先分区,还可以有效解决数据倾斜的问题,我们可以把频繁访问的数据,放到多个region中,把不常访问数据,放入到一个或者几个region中。
  • RowKey的优化
    1.可以根据三维对数据快速定位rowkey+cf:qualifer+timestamp
    rowkey可以快速定位一条记录,两种方式,get 根据rowkey获取某一条记录,也可以scan 通过startrow 和stoprow进行范围查找
    2.利用HBase默认排序的特点,将一起访问的数据放到一起
    3.防止热点问题,避免使用时序或者单调递增或者递减等。
    热点问题,就是在分布式系统中,大量的client去访问集群中的一个或者极少数的几台机器,造成热点机器,超出自身处理能力,从而造成整个集群出现问题。
    如果解决热点问题呢? 可以通过加盐,也就是加随机数,或者hash,反转等方式,来解决rowkey可能存在的热点问题。
    4.rowkey的长度应该尽可能短,过长对regionserver的磁盘,内存都会过大的消耗。
  • Column的优化
    1.列明和列描述名称尽可能短
    2.HBase对多个cf的支持并不好,建议一个表中的cf 最好不要超过三个
  • Schema的优化
    HBase表在设计的时候,很可能根据业务设置成宽表(一种“列多行少的设计”)或者高表(一种“行少列多”的设计)
    高表:查询性能高,吞吐量大,缓存更多的行,元数据开销更大(rowkey多,region多)
    宽表:事务性更好,HBase事务是建立在行上的,宽表,一个行有多个列,可以有效保证事务性。
    设计表的时候,没必要追求高表,宽表,要根据业务进行选择。

HBase 读写性能优化

HBase写优化策略
  • 同步批量提交 or 异步批量提交
    默认是同步提交,要么全部成功,要么抛出异常,异步提交,有可能会丢失数据,如果为了提高性能,又能够忍受异常情况下部分数据丢失,可以使用异步提交方式,可以大大提升,写入性能。
  • WAL优化,是否必须,持久化等级
    WAL有两个作用,一个是防止memstore中数据丢失了,可以根据memstore中的数据进行恢复,另一个就是集群中不同HBase节点间的异步复制,默认是开启WAL的。如果业务允许,对于异常情况下的部分数据丢失可以忍受,更关系写入的吞吐量,这个时候可以考虑关闭掉WAL,或者采用异步写入WAL,这些都能够提升写入性能,但是对于写入数据的完整性无法保证。
HBase读优化策略
  • 客户端:Scan缓存设置,批量获取
    客户端在读取的时候,可以设置缓存大小,通常来说,一次读取,会返回大量的数据,客户端在通过scan检索数据的时候,实际上不会一次就返回所有的数据,而是会多次通过rpc请求加载,这样设计一方面是因为大量的io请求,可以会导致网络带宽严重消耗,进而影响其他,业务,另一方面,一次返回太多的数据,导致客户端发生内存溢出。客户端首先加载一部分数据到本地,然后遍历,然后再去加载一部分数据,然后遍历。。。
    如果数据量非常大,可以适当调大一点cache的大小,减少rpc请求的次数。
    检索的时候,我们需要指定列簇,因为一个表,可能有多个列簇,每一个列簇存储在不同的region中,如果不指定列簇,那么检索的数据量就比较大了。
  • 服务端:BlockCache配置是否合理,HFile是否过多
    如果BlcokCache 如果不能够命中,那么HFile 如果过多,那么又会非常影响性能,因为多个HFile会增加磁盘寻址时间,因此需要执行compact,对文件进行合并。
  • 表结构设计问题:根据具体业务,对表结构进行设计 优化。