美团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

时间: 2024-08-01 08:45:28

美团Apache Kylin精确去重指标优化历程的相关文章

Apache Kylin中对上亿字符串的精确Count_Distinct示例

如果业务中能接受1.22%的误差,那么肯定首选近似算法,因为它能节省很多资源和时间.如果业务中必须使用精确去重,那么就看看本文的例子(针对上亿字符串的精确去重). 事实表 hive> desc test_t_pbs_uv_fact;  OK  ad_id                   string  //维度  material_id             string   //维度  city_code               string  //维度  user_id      

Apache Kylin优化之—Cube的高级设置

随着维度数目的增加,Cuboid 的数量会爆炸式地增长.为了缓解 Cube 的构建压力,Apache Kylin 引入了一系列的高级设置,帮助用户筛选出真正需要的 Cuboid.这些高级设置包括聚合组(Aggregation Group).联合维度(Joint Dimension).层级维度(Hierachy Dimension)和必要维度(Mandatory Dimension)等." 众所周知,Apache Kylin 的主要工作就是为源数据构建 N 个维度的 Cube,实现聚合的预计算.理

Apache Kylin优化–高级设置:聚合组(Aggregation Group)原理解析

"随着维度数目的增加,Cuboid 的数量会爆炸式地增长.为了缓解 Cube 的构建压力,Apache Kylin 引入了一系列的高级设置,帮助用户筛选出真正需要的 Cuboid.这些高级设置包括聚合组(Aggregation Group).联合维度(Joint Dimension).层级维度(Hierachy Dimension)和必要维度(Mandatory Dimension)等." 众所周知,Apache Kylin 的主要工作就是为源数据构建 N 个维度的 Cube,实现聚合

Apache Kylin权威指南1.5 Apache Kylin的主要特点

1.5 Apache Kylin的主要特点 Apache Kylin的主要特点包括支持SQL接口.支持超大数据集.秒级响应.可伸缩性.高吞吐率.BI工具集成等. 1.5.1 标准SQL接口 Apache Kylin以标准SQL作为对外服务的主要接口.因为SQL是绝大多数分析人员最熟悉的工具,同时也是大多数应用程序使用的编程接口.尽管Kylin内部以Cube技术为核心,对外却没有选用MDX(MultiDimensional eXpressions)作为接口.虽然MDX作为OLAP查询语言,从学术上

Apache Kylin权威指南导读

前 言 "麒麟出没,必有祥瑞." --中国古谚语 "于我而言,与Apache Kylin团队一起合作使Kylin通过孵化成为顶级项目是非常激动人心的,诚然,Kylin在技术方面非常振奋人心,但同样令人兴奋的是Kylin代表了亚洲国家,特别是中国,在开源社区中越来越高的参与度." --Ted Dunning Apache孵化项目副总裁,MapR首席应用架构师 今天,随着移动互联网.物联网.AI等技术的快速兴起,数据成为了所有这些技术背后最重要,也是最有价值的"

Apache Kylin:基于Hadoop的OLAP引擎

传统上,Hadoop(包括MapReduce,Pig以及Hive)通常用于外部私有OLAP Cube引擎准备数据.如今,Zaloni的客户基于Apache Kylin的OLAP技术实现了实时查询的能力,这些Cube的事实表包含了400亿条以上的原始数据.我们正在帮助客户统一归集来自于多个独立系统的账单数据,并构建OLAP Cube以支持实时分析,这是以前系统所无法实现的.现在,Hadoop集群都可以做到了. 基于Hadoop的分析演化 Hadoop已经从通用计算能力(MapReduce)的分布式

Apache 基金会宣布 Apache Kylin 成为顶级项目

Apache Kylin 是可扩展到PB规模的开源分布式大数据分析引擎,已被应用在eBay,Exponential, 京东,美团,明略数据,网易及其他公司. 马里兰州 Forest Hill - 2015年12月8日 -由超过350个开源项目及创新计划,全部由开发志愿者,治理志愿者及孵化志愿者组成的 Apache软件基金会(ASF),今天宣布Apache Kylin已经从Apache孵化器项目毕业,正式升级成为顶级项目(TLP),这标志着该项目的社区和产品依照ASF精英管理的流程和原则顺利运作.

Apache Kylin发布新版流处理引擎

Apache Kylin在 1.5.0 推出了从流数据进行准实时(Near Real Time)处理功能,可以直接从Apache Kafka的主题(Topic)中消费数据来构建Cube.Apache Kylin 1.5.0的流处理是一次实验性的探索,它打破了以往只能从Apache Hive表构建Cube的局限,将数据从产生到可查询的延迟从小时级降低到了分钟级,满足了一些对实时性要求比较高的场景:但它在实现上存在一些局限︰ 不可扩展︰ 由于是利用单个 Java 进程(而不是利用某种计算框架)对数据

Apache Kylin权威指南1.2 Apache Kylin的使命

1.2 Apache Kylin的使命 Kylin的使命是超高速的大数据OLAP(Online Analytical Processing),也就是要让大数据分析像使用数据库一样简单迅速,用户的查询请求可以在秒内返回,交互式数据分析将以前所未有的速度释放大数据里潜藏的知识和信息,让我们在面对未来的挑战时占得先机. 1.2.1 为什么要使用Apache Kylin 自从10年前Hadoop诞生以来,大数据的存储和批处理问题均得到了妥善解决,而如何高速地分析数据也就成为了下一个挑战.于是各式各样的"