美团Apache Kylin精确去重指标优化历程

简介:

美团Apache Kylin精确去重指标优化历程

康凯森,美团点评大数据工程师,Apache Kylin commiter,目前主要负责Apache Kylin在美团点评的平台化建设。

问题背景

本文记录了我将Apache Kylin超高基数的精确去重指标查询提速数十倍的过程,大家有任何建议或者疑问欢迎讨论。

某业务方的cube有12个维度,35个指标,其中13个是精确去重指标,并且有一半以上的精确去重指标单天基数在千万级别,cube单天数据量1.5亿行左右。业务方一个结果仅有21行的精确去重查询竟然耗时12秒多,其中HBase端耗时6秒多,Kylin的query server端耗时5秒多:


 
 
  1. SELECT A, B, count(distinct uuid), FROM table WHERE dt = 17150 GROUP BY A, B 

精确去重指标已经在美团点评生产环境大规模使用,我印象中精确去重的查询的确比普通的Sum指标慢一点,但也挺快的。这个查询慢的如此离谱,我就决定分析一下,这个查询到底慢在哪。

优化1 将精确去重指标拆分HBase列族

我首先确认了这个cube的维度设计是合理的,这个查询也精准匹配了cuboid,并且在HBase端也只扫描了21行数据。

那么问题来了,为什么在HBase端只扫描21行数据却需要6秒多?一个显而易见的原因是Kylin的精确去重指标是用bitmap存储的明细数据,而这个cube有13个精确去重指标,并且基数都很大。我从两方面验证了这个猜想:

1.同样SQL的查询Sum指标只需要120毫秒,并且HBase端Scan仅需2毫秒。

2.我用HBase HFile命令行工具查看并计算出HFile中单个KeyValue的大小,发现普通指标的列族中每个KeyValue平均大小是29B,精确去重指标列族的每个KeyValue平均大小却有37M。

所以我第一个优化就是将精确去重指标拆分到多个HBase列族,优化后的效果十分明显。查询时间从12秒多减少到5.7秒左右,HBase端耗时从6秒多减少到1.3秒左右,不过query server耗时依旧有4.5秒多。

优化2 移除不必要的toString避免bitmap deserialize

Kylin的query server耗时依旧有4.5秒多,我猜测肯定还是和bitmap比较大有关,但是为什么bitmap大会导致如此耗时呢?为了分析query server端查询处理的时间到底花在了哪,我利用Java Mission Control进行了性能分析。

JMC分析很简单,在Kylin的启动进程中增加以下参数:


 
 
  1. -XX:+UnlockCommercialFeatures -XX:+FlightRecorder  
  2. -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints  
  3. -XX:StartFlightRecording=delay=20s,duration=300s,name=kylin,filename=myrecording.jfr,settings=profile  

获得myrecording.jfr文件后,我们在本机执行jmc命令,然后打开myrecording.jfr文件就可以进行性能分析。从jmc的热点代码图中我们发现,耗时最多的代码竟然是一个毫无意义的toString。去掉这个toString之后,query server的耗时直接减少了1秒多。

优化3 获取bitmap的字节长度时避免deserialize

在优化2去掉无意义的toString之后,热点代码已经变成了对bitmap的deserialize。不过bitmap的deserialize共有两处,一处是bitmap本身的deserialize,一处是在获取bitmap的字节长度时。于是很自然的想法就是是在获取bitmap的字节长度时避免deserialize bitmap,当时有两种思路:

1.在serialize bitmap时就写入bitmap的字节长度。

2.在MutableRoaringBitmap序列化的头信息中获取bitmap的字节长度。(Kylin的精确去重使用的bitmap是RoaringBitmap)

我最终确认思路2不可行,采用了思路1。

思路1中一个显然的问题就是如何保证向前兼容,我向前兼容的方法就是根据MutableRoaringBitmap deserialize时的cookie头信息来确认版本,并在新的serialize方式中写入了版本号,便于之后序列化方式的更新和向前兼容。

经过这个优化后,Kylin query server端的耗时再次减少1秒多。

优化4 无需上卷聚合的精确去重查询优化

从精确去重指标在美团点评大规模使用以来,我们发现部分用户的应用场景并没有跨segment上卷聚合的需求,即只需要查询单天的去重值,或是每次全量构建的cube,也无需跨segment上卷聚合。所以我们希望对无需上卷聚合的精确去重查询进行优化,当时我考虑了两种可行的方案:

方案1: 精确去重指标新增一种返回类型

一个极端的做法是对无需跨segment上卷聚合的精确去重查询,我们只存储最终的去重值。

优点:

1.存储成本会极大降低。

2.查询速度会明显提高。

缺点:

1.无法支持上卷聚合,与Kylin指标的设计原则不符合。

2.无法支持segment的merge,因为要进行merge必须要存储明细的bitmap。

3.新增一种返回类型,对不清楚的用户可能会有误导。

4.查询需要上卷聚合时直接报错,用户体验不好,尽管使用这种返回类型的前提是无需上聚合卷。

实现难点:

如果能够接受以上缺点,实现成本并不高,目前没有想到明显的难点。

方案2:serialize bitmap的同时写入distinct count值。

优点:

1.对用户无影响。

2.符合现在Kylin指标和查询的设计。

缺点:

1.存储依然需要存储明细的bitmap。

2.查询速度提升有限,因为即使不进行任何bitmap serialize,bitmap本身太大也会导致HBase scan,网络传输等过程变慢。

实现难点:

如何根据是否需要上卷聚合来确定是否需要serialize bitmap?

解决过程:

我开始的思路是从查询过程入手,确认在整个查询过程中,哪些地方需要进行上卷聚合。为此,我仔细阅读了Kylin query server端的查询代码,HBase Coprocessor端的查询代码,Calcite的example例子。发现在HBase端,Kylin query server端,cube build时都有可能需要指标的聚合。

此时我又意识到一个问题:即使我清晰的知道了何时需要聚合,我又该如何把是否聚合的标记传递到精确去重的反序列方法中呢?现在精确去重的deserialize方法参数只有一个ByteBuffer,如果加参数,就要改变整个kylin指标deserialize的接口,这将会影响所有指标类型,并会造成大范围的改动。所以我把这个思路放弃了。

后来我"灵光一闪",想到既然我的目标是优化无需上卷的精确去重指标,那为什么还要费劲去deserialize出整个bitmap呢,我只要个distinct count值不就完了。所以我的目标就集中在BitmapCounter本身的deserialize上,并联想到我最近提升了Kylin前端加载速度十倍以上的核心思想:延迟加载,就改变了BitmapCounter的deserialize方法,默认只读出distinct count值,不进行bitmap的deserialize,并将那个buffer保留,等到的确需要上卷聚合的时候再根据buffer deserialize 出bitmap。

当然,这个思路可行有一个前提,就是buffer内存拷贝的开销是远小于bitmap deserialize的开销,庆幸的是事实的确如此。最终经过这个优化,对于无需上卷聚合的精确去重查询,查询速度也有了较大提升。显然,如你所见,这个优化加速查询的同时加大了需要上卷聚合的精确去重查询的内存开销。我的想法是首先对于超大数据集并且需要上卷的精确去重查询,用户在分析查询时返回的结果行数应该不会太多,其次我们需要做好query server端的内存控制。

总结

我通过总共4个优化,在向前兼容的前提下,后端仅通过100多行的代码改动,对Kylin超高基数的精确去重指标查询有了明显提升,测试中最明显的查询有50倍左右的提升。


本文作者:康凯森

来源:51CTO

相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
  相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情: https://cn.aliyun.com/product/hbase   ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
消息中间件 监控 大数据
优化Apache Kafka性能:最佳实践与调优策略
【10月更文挑战第24天】作为一名已经对Apache Kafka有所了解并有实际使用经验的开发者,我深知在大数据处理和实时数据流传输中,Kafka的重要性不言而喻。然而,在面对日益增长的数据量和业务需求时,如何保证系统的高性能和稳定性成为了摆在我们面前的一个挑战。本文将从我的个人视角出发,分享一些关于如何通过合理的配置和调优来提高Kafka性能的经验和建议。
115 4
|
3月前
|
消息中间件 分布式计算 大数据
大数据-166 Apache Kylin Cube 流式构建 整体流程详细记录
大数据-166 Apache Kylin Cube 流式构建 整体流程详细记录
110 5
|
3月前
|
存储 SQL 分布式计算
大数据-162 Apache Kylin 全量增量Cube的构建 Segment 超详细记录 多图
大数据-162 Apache Kylin 全量增量Cube的构建 Segment 超详细记录 多图
80 3
|
3月前
|
Java 大数据 数据库连接
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
67 2
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
|
3月前
|
SQL 分布式计算 NoSQL
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
51 1
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
|
3月前
|
SQL 存储 分布式计算
大数据-157 Apache Kylin 背景 历程 特点 场景 架构 组件 详解
大数据-157 Apache Kylin 背景 历程 特点 场景 架构 组件 详解
56 9
|
3月前
|
分布式计算 大数据 分布式数据库
大数据-158 Apache Kylin 安装配置详解 集群模式启动(一)
大数据-158 Apache Kylin 安装配置详解 集群模式启动(一)
74 5
|
3月前
|
SQL 分布式计算 大数据
大数据-160 Apache Kylin 构建Cube 按照日期构建Cube 详细记录
大数据-160 Apache Kylin 构建Cube 按照日期构建Cube 详细记录
64 2
|
3月前
|
资源调度 大数据 分布式数据库
大数据-158 Apache Kylin 安装配置详解 集群模式启动(二)
大数据-158 Apache Kylin 安装配置详解 集群模式启动(二)
65 2
|
3月前
|
存储 大数据 分布式数据库
大数据-165 Apache Kylin Cube优化 案例 2 定义衍生维度及对比 & 聚合组 & RowKeys
大数据-165 Apache Kylin Cube优化 案例 2 定义衍生维度及对比 & 聚合组 & RowKeys
61 1

热门文章

最新文章

推荐镜像

更多