查询优化
批量get请求
使用批量请求,可以减少RPC的次数,显著提高吞吐量。批量get请求要么成功返回所有请求数据,要么抛出异常。
设置Scan缓存
一次scan可能会返回大量数据,但是实际客户端发起一次scan请求,并不会将所有数据一次性加载到本地,而是分成多次RPC请求进行加载,这样设计一方面是因为大量数据请求可能会导致网络带宽严重消耗进而影响其他业务,另一方面是有可能因为数据量太大导致客户端发生OOM。所以采用先加载一部分数据到本地,然后进行遍历,每次加载一部分数据,如此往复,直至所有数据加载完成。数据加载到本地就存放在scan缓存中,默认100。
通常情况下,默认的scan缓存设置就可以正常工作的。但是在一些大scan(一次scan可能需要查询几万甚至几十万行数据)来说,每次请求100条数据意味着一次scan需要几百甚至几千次RPC请求,这种交互的代价无疑是很大的。因此可以考虑将scan缓存设置增大。
指定读取的列
HBase是列族数据库,同一列族的数据存储在一块,不同列族是分开存储的,如果一个表由多个列族,只是根据RowKey而不指定列族进行检索的话,不同列族的数据需要独立进行检索,性能必然会比指定列族的查询差的多。
此外指定请求的列的话,不需要将整个列族的所有列的数据返回,这样就减少了网路IO。
关闭ResultScanner
在使用table.getScanner之后,记得关闭,否则它会和服务器端一直保持连接,资源无法释放,从而导致服务端的某些资源不可用。
禁用块缓存
当离线访问HBase时,往往会对HBase表进行扫描,此时读取的数据没有必要存放在BlockCache中,否则会降低扫描的效率。
建议在对HBase表进行扫描时禁用缓存。
对于频繁查询HBase的应用场景不需要禁用缓存,并且可以考虑在应用程序和HBase之间加一层缓存系统(如Redis),先查询缓存,缓存没有命中再去查询HBase。
写入优化
批量写
使用批量写,可以减少客户端到RegionServer之间的RPC的次数,提高写入性能。*批量写请求要么全部成功返回,要么抛出异常。
多线程并发写
客户端开启多个HTable写线程,每个写线程负责一个HTable对象的flush操作,这样结合定时flush和写buffer,可以即保证在数据量小的时候,数据可以在较短时间内被flush,同时又保证在数据量大的时候,写buffer一满就即使进行flush。
BulkLoad写入
使用MapReduce或者Spark直接生成HFile格式的数据文件,然后再通过RegionServer将HFile数据文件移动到相应的Region上去。
BulkLoad不会写WAL,也不会产生flush以及split
如果我们大量调用PUT接口插入数据,可能会导致大量的GC操作。除了影响性能之外,严重时甚至可能会对HBase节点的稳定性造成影响。但是采用BulkLoad就不会有影响性能。
合理设置WAL存储级别
客户端向集群中的RegionServer提交数据时(Put/Delete操作),首先会先写WAL(Write Ahead Log)日志(即HLog,一个RegionServer上的所有Region共享一个HLog),只有当WAL日志写成功后,再接着写MemStore,然后客户端被通知提交数据成功;如果写WAL日志失败,客户端则被通知提交失败。这样做的好处是可以做到RegionServer宕机后的数据恢复。默认WAL机制是开启的,并且使用的是同步机制写WAL。
如果业务不特别关心异常情况下部分数据的丢失,而更关心数据写入吞吐量,可考虑关闭WAL写,这样可以提升2~3倍数据写入的吞吐量。
如果业务不能接受不写WAL,但是可以接受WAL异步写入,这样可以带了1~2倍性能提升。
HBase中可以通过设置WAL的持久化等级决定是否开启WAL机制、以及HLog的落盘方式。
WAL的持久化等级分为如下四个等级:
SKIP_WAL:只写缓存,不写HLog日志。这种方式因为只写内存,因此可以极大的提升写入性能,但是数据有丢失的风险。在实际应用过程中并不建议设置此等级,除非确认不要求数据的可靠性。
ASYNC_WAL:异步将数据写入HLog日志中。
SYNC_WAL:同步将数据写入日志文件中,需要注意的是数据只是被写入文件系统中,并没有真正落盘,默认。
FSYNC_WAL:同步将数据写入日志文件并强制落盘。最严格的日志写入等级,可以保证数据不会丢失,但是性能相对比较差。
设置AutoFlush
可以将HTable写客户端的自动flush关闭,这样可以批量写入数据到HBase,而不是有一条put就执行一次更新,只有当put填满客户端写缓存时,才实际向HBase服务端发起写请求。默认情况下auto flush是开启的。
预创建Region
在HBase中数据是分布在各个Region中的,每个Region都负责一个起始RowKey和结束Rowkey的范围,在向HBase中写数据的时候,会根据RowKey请求到对应的Region上,如果写请求都集中在某一个Region或某几个Region上的时候,性能肯定不如写请求均匀分布在各个Region上好。默认情况下,创建的HBase的只有一个Region分区,会随着数据量的变大,进行split,拆分成多个Region,最开始的性能肯定会很不好
建议在设计HBase的的时候,进行预分区,并设计一个良好的Rowkey生成规则,尽量将数据分散到各个Region上,那样在进行HBase的读写的时候,对性能会有很好的改善。