一张Hive计算完成后,开发者会希望知道计算结果是否符合预期,比如是否有脏数据,是否数据量符合预期。这里就有两个问题,一个是校验什么,另一个是怎么校验。
校验什么
- 单个字段校验,例如字段的唯一性、非空、数值范围、枚举类型、异常值
- 表级行数,例如表的行数在一个合理范围,可以是跟历史行数对比,也可以跟预设的常量做对比
- 业务逻辑校验,包括了表内、表间的比较
怎么执行校验
Hive表的校验自然是跑SQL最方便,每当Hive表更新完要执行SQL校验,需要考虑两个问题
- 资源消耗。最基本的采集表行数,再加上额外的校验规则,不应该占用太多计算资源,以免因为校验而拖慢集群整体性能
- 校验延迟。如果是大表,或者是复杂规则,马上获取到校验结果是比较困难的。当校验与调度打通,应当认为关键规则必须校验通过,这种关键校验就不能等待太久。还有一种交互式的校验场景,用户配置完规则后,需要立即测试查看执行情况。
基于上述考虑,就要选择既省资源,又快的计算引擎,MapReduce可直接排除,备选方案是Spark SQL和Presto。
回过头看校验要执行的SQL,大部分是简单SQL,例如count(), min/max等,Presto在这种简单查询展示出了非常优异的性能,无论消耗资源,还是执行时间都很好。实际测试中,一张2亿行的表查询最新的总行数,执行select count() from table_name,只消耗了2.4 CPU-Second,执行时长也是2秒左右,消耗的资源和运行时长都可忽略不计。Presto跑的快的原因有很多,不用去yarn上申请资源,对orc文件查询做了很多优化,简单查询会直接基于orc的meta做计算,具体原因就不在赘述。
相同的SQL,Spark SQL一般的执行时间都要多很多,消耗的资源也会更多。不过两着对资源的计算方法肯定是不一样的,所以不能完全保证Presto更省资源,此处没有严格考证。
还有一些复杂的SQL,比如大表的字段唯一性校验,Presto很容易出现内存不足的异常,这时候可以考虑切换到Spark SQL来执行,至少保证能运行成功。
如何触发校验
- 实时,当表完成更新时触发。我们把调度系统与数据质量校验打通,让表完成更新时,会调用接口触发执行校验,并有另一个接口可查询是否校验成功
- 后置任务,把校验也看做是一种离线计算任务,作为原任务的下游
- 定时
扩展功能
我们记录了每个枚举值,在表中出现的次数,每天记录一个值,久而久之可以形成变化趋势,可以发现某些业务细节的波动,发现异常的用户行为。
还尝试了对关键业务指标做了统计值校验,比如N个商品销量的最大最小、中位数、90%位数、平均数、标准差等,同样是每天采集并形成变化趋势,可以发现异常业务情况,Presto自带了这些算法。
实际使用效果
在数仓小组内部,给重要表加上规则,再也不用担心报表出现重大问题,而一无所知。
功能上线后有冷启动的问题,用户不了解,也不能感知产品价值,所以很少有用户主动配置。于是我们通过默认的表级行数波动校验,采集每次表更新完的最新行数,发现异常波动,帮助用户发现问题,逐渐吸引用户使用。偶尔还会有用户惊叹,这么隐蔽的问题也能被发现,这就体现了业务监控的价值。随后我们通过培训、开发者访谈等方式,逐步推广。
后续有不少开发者,纯粹为了执行校验规则,发现业务异常数据,而把业务数据导入Hive中。也有DBA来查看采集到的数据量波动,来观察DB的数据量增长情况。
关于数据质量的更多话题
数据质量是个很大话题,除了数据准确性,至少还包括数据产出及时性、表间的数据一致性,用户甚至会把任何的数据看不懂都认为是数据质量问题,有些可能只是理解上的偏差。给Hive表配置了数据质量校验规则,只是一定程度保证了准确性,要真正解决数据质量问题,还需要更多技术和规范的努力。