2019/3/7 星期四
深入探讨为什么hbase读数据(scan)性能底下
简述: 和写流程对比起来,HBase读数据是一个更加复杂的操作流程,这主要基于两个方面的原因: 其一是因为整个HBase存储引擎基于LSM-Like树实现,因此一次范围查询可能会涉及多个分片、多块缓存甚至多个数据存储文件; 其二是因为HBase中更新操作以及删除操作实现都很简单,更新操作并没有更新原有数据,而是使用时间戳属性实现了多版本。删除操作也并没有真正删除原有数据,只是插入了一条打上”deleted”标签的数据,而真正的数据删除发生在系统异步执行Major_Compact的时候。 很显然,这种实现套路大大简化了数据更新、删除流程,但是对于数据读取来说却意味着套上了层层枷锁,读取过程需要根据版本进行过滤,同时对已经标记删除的数据也要进行过滤。
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的一个列也会形成很多文件,但是好像并没影响它的性能
小结:
- HBase不完全是列式存储,确切的说是列族式存储,HBase中可以定义一个列族,列族下可以有都个列,这些列的数据是存在一起的。而且通常情况下我们建议列族个数不大于2个,这样的话每个列族下面必然会有很多列。因此HBase并不是列式存储,更有点像行式存储。//细微的解释,个人观点
- HBase扫描本质上是一个一个的随即读,不能做到像HDFS(Parquet)这样的顺序扫描。试想,1000w数据一条一条get出来,性能必然不会很好。问题就来了,HBase为什么不支持顺序扫描?
- 这是因为HBase支持更新操作以及多版本的概念,这个很重要。可以说如果支持更新操作以及多版本的话,扫描性能就不会太好。原理是这样的,我们知道HBase是一个类LSM数据结构,数据写入之后先写入内存,内存达到一定程度就会形成一个文件,因此HBase的一个列族会有很多文件存在。因为更新以及多版本的原因,一个数据就可能存在于多个文件,所以需要一个文件一个文件查找才能定位出具体数据。 所以HBase架构本身个人认为并不适合做大规模scan,很大规模的scan建议还是用Parquet,可以把HBase定期导出到Parquet来scan 再问:
个人对Kudu不是很懂,不过旁边有Kudu大神。我的理解是这样的:
- kudu性能并没有达到parquet的扫描速度,可以说介于HBase和HDFS(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/