原文:https://blog.51cto.com/12445535/2359652
与写流程对比起来,HBase读数据是一个更加复杂的操作流程,这主要基于两个方面的原因:
其一是因为整个HBase存储引擎基于LSM-Tree实现,因此一次范围查询可能会涉及多个分片、多块缓存甚至多个数据存储文件;
其二是因为HBase中更新操作以及删除操作实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本。删除操作也并没有真正删除原有数据,只是插入了一条打上"deleted"标签的数据,而真正的数据删除发生在系统异步执行Major_Compact的时候。
很显然,这种实现套路大大简化了数据更新、删除流程,但是对于数据读取来说却意味着套上了层层枷锁,读取过程需要根据版本进行过滤,同时对已经标记删除的数据也要进行过滤。
Scan流程
1、一次scan请求,先在客户端缓存中找,如果找到了后,就直接返回给客户端。
2、如果没有找到再在 BlockCache、HFile以及memcache 中一行一行进行扫描,扫到100行之后,就返回给客户端。
3、客户端将这100行数据缓存到内存中并返回给一条给上层业务。
这里是每次都会调用100行数据,客户端拿到之后,再扫描100条数据,直到数据被全部拿到。
上层业务不断一条一条获取扫描数据,在数据量大的情况下实际上HBase客户端会不断发送next请求到HBase服务器。有的朋友可能会问为什么scan需要设计为多次next请求的模式?个人认为这是基于多个层面的考虑:
1、HBase本身存储了海量数据,所以很多场景下一次scan请求的数据量都会比较大。如果不限制每次请求的数据集大小,很可能会导致系统带宽吃紧从而造成整个集群的不稳定。
2、如果不限制每次请求的数据集大小,很多情况下可能会造成客户端缓存OOM掉。
3、如果不限制每次请求的数据集大小,很可能服务器端扫描大量数据会花费大量时间,客户端和服务器端的连接就会timeout。
get的批处理操作是按照目标region进行分组,不同分组的get请求会并发执行读取。然而scan并没有这样实现。
也就是说,scan不是并行操作。
所以从客户端角度来看整个扫描时间=客户端处理数据时间+服务器端扫描数据时间,这能不能优化?
根据上面的分析,scan API的效率很大程度上取决于扫描的数据量。通常建议OLTP业务中少量数据量扫描的scan可以使用scan API。大量数据的扫描使用scan API,扫描性能有时候并不能够得到有效保证。
引出问题
HBase作为列式存储,为什么它的scan性能这么低呢,列式存储不是更有利于scan操作么?Parquet格式也是列式,但它的scan这么优秀,他们的性能差异并不是因为数据组织方式造成的么?Kudu也是采用的类LSM数据结构,但是却能达到Parquet的扫描速度(Kudu是纯列式的),Kudu的一个列也会形成很多文件,但是好像并没影响它的性能。
小结
1、HBase不完全是列式存储,确切的说是列族式存储,HBase中可以定义一个列族,列族下可以有都个列,这些列的数据是存在一起的。而且通常情况下我们建议列族个数不大于2个,这样的话每个列族下面必然会有很多列。因此HBase并不是列式存储,更有点像行式存储。
2、HBase扫描本质上是一个一个的随即读,不能做到像HDFS(Parquet)这样的顺序扫描。试想,1000w数据一条一条get出来,性能必然不会很好。
那么问题就来了,HBase为什么不支持顺序扫描?
这是因为HBase支持更新操作以及多版本的概念,这个很重要。可以说如果支持更新操作以及多版本的话,扫描性能就不会太好。原理是这样的,我们知道HBase是一个类LSM数据结构,数据写入之后先写入内存,内存达到一定程度就会形成一个文件,因此HBase的一个列族会有很多文件存在。因为更新以及多版本的原因,一个数据就可能存在于多个文件,所以需要一个文件一个文件查找才能定位出具体数据。
所以HBase架构本身个人认为并不适合做大规模scan,很大规模的scan建议还是用Parquet,可以把HBase定期导出到Parquet来scan。
3、Kudu性能并没有达到Parquet的扫描速度,可以说介于HBase和Parquet之间:
- Kudu比HBase扫描性能好,是因为Kudu是纯列存,扫描不会出现跳跃读的情况,而HBase可能会跳跃seek。这是本质的区别。
- 但Kudu扫描性能又没有Parquet好,就是因为Kudu是LSM结构,它扫描的时候还是会同时顺序扫描多个文件,并比较key值大小。而Parquet只需要顺序对一个block块中的数据进行扫描即可。这个是两者的区别。
所以说HBase相比Parquet,这两个方面都是scan的劣势。
参考链接:
HBase原理-数据读取流程解析
http://hbasefly.com/2016/12/21/hbase-getorscan/
HBase最佳实践 – Scan用法大观园
http://hbasefly.com/2017/10/29/hbase-scan-3/