文章目录
随着用户分析数据量的急剧增长与用户多维实时交互分析数据的需求,OLAP引擎成了交互式数据分析的标配。
<1%的“异常”查询影响OLAP引擎的稳定性
如何保证让OLAP引擎能稳定高效地提供数据服务,是普遍面临的一个问题。而影响OLAP引擎稳定性的一大原因是来自用户的“异常”查询:用户由于错误操作或确实基于合理需求而触发的大查询可能会挤占整个集群的资源甚至会让集群崩溃,从而影响到其他用户的正常使用,甚至造成数据的丢失。
通常的做法是拦截或者采用其他计算引擎如SparkSQL来处理这些“异常”查询,这都首先要求能很好的识别这些“异常”查询。
基于规则判断的方式比较粗糙,只能解决部分问题
首先想到的是基于预定规则判断的方式来识别并拦截用户的大查询,这也是目前大多数系统的解决方案。一般是通过限制用户查询数据的时间跨度与同时查询展开的维度两个视角来进行识别拦截,如:
- 用户的查询跨度不能超过3个月;
- 用户查询的展开维度不能同时超过5个;
由于规则依据比较简单固定,不能根据数据的特性进行调整,因此识别“异常”查询的准确度比较差。这种方案存在以下不足:
- OLAP引擎多采用列存储,那在限制查询时间跨度时是不是需要根据用户查询的字段数量进行动态调整?
- 不同字段数据类型及其数据内容差异很大,是不是也应该差异对待?
- 不同维度的基数差异很大,且会随着时间变化,在限制维度展开时是不是应该根据维度的基数进行动态调整?
基于规则判断的方式比较粗糙,只能解决部分问题。那有更加智能的方式识别“异常”查询吗?
借鉴数据库Query Optimizer思想建立查询成本指标
总结分析发现“异常”查询主要有两大特点:
- 一是因为扫描处理的数据量太大从而占用过多的集群资源,影响对其他用户查询的响应;
- 二是由于返回的结果集太大对节点造成很大的内存压力,甚至导致集群节点OOM崩溃。
因此识别“异常”查询问题的本质就是计算评估查询的成本,这自然联想到关系数据库的Query Optimizer。数据库的优化器有两大类:基于规则的RBO优化器和基于成本的CBO优化器。RBO规则优化器只能承载一些明确的、简单的预定义规则,应用范围比较有限。而基于成本的CBO优化器被所有数据库广泛使用,不一样的只是不同数据库会定义不同的成本指标与优化函数。因此可以建立评估“异常”查询的成本指标:
COST1 = 扫描数据量
COST2 = 返回结果集
“异常”查询 = COST1 > Threshold1 or COST2 > Threshold1
这样识别“异常”查询的问题就转化为对扫描数据量和返回结果集大小的预估,并根据其对集群稳定性影响的大小来评估确定两个阈值。
扫描数据量预估
目前几乎所有的OLAP引擎都采用列存储来存储数据,相比行存储来说需要扫描的数据量小并且数据压缩率更高。由于列存储中不同列是分开独立存储的,则可以根据用户查询需要扫描的列以及各列占用存储的大小来评估查询要扫描的数据量。
// row_number表示查询时间范围内的总行数
// col1_bytes、col2_bytes分别表示各列数据占用的平均字节大小
扫描数据量 = row_number * (col1_bytes + col2_bytes + ...)
OLAP引擎为了加速查询都会对各列数据建立稀疏索引,同时在BI系统中用户的查询往往会带有一些筛选项(通常是对维度的某几个枚举进行筛选,而且各维度间的筛选条件是与的方式联结),那是不是可以对上述的评估方法进行修正?如果能根据维度列的筛选项对满足筛选条件的数据量进行预估(可依据下一小节的直方图统计信息预估),则可以将扫描数据量预估方法进行修正:
// col1_row_number、col2_row_number分别表示各列满足筛选条件的行数,如该列没有筛选条件,则其等于总行数row_number
// col1_bytes、col2_bytes分别表示各列数据占用的平均字节大小
扫描数据量 = (col1_row_number * col1_bytes + col2_row_number * col2_bytes + ...)
维度类型可分为可枚举的维度和不可枚举的维度。对于可枚举维度来说,用户往往是给定几个筛选项来进行选择ÿ