Kyligence AI 服务 - 让大模型完成准确、可靠的数值计算和回答! 立即了解更多
AI 数智助理
Kyligence Zen Kyligence Zen
Kyligence Enterprise Kyligence Enterprise
Kyligence Turbo Kyligence Turbo
指标平台解决方案
OLAP 解决方案
行业解决方案
客户总览
金融
零售
制造
医药
其他
云平台
BI
寻求合作
资源
Kyligence Enterprise
Kyligence Zen
培训
Apache Kylin
Byzer
Gluten
博客
关于
市场活动
本文作者李宗伟,系思科工程师,是思科大数据架构团队成员,目前主要负责OLAP平台搭建及客户业务报表系统的研发。
我们是来自于Cisco大数据团队的开发小组,其中一项业务是为客户提供BI报表:客户会登录报表系统查询Cisco业务的使用情况,也会将它作为计费账单的参考,这些报表对客户而言是非常重要的业务功能。
这些报表数据来自于多张Oracle数据库中的表,单张表单月的数据量在亿级,也就是说,如果客户想查询一年的报表,至少需要对十亿到二十亿的数据做聚合查询等操作,同时需要在很短的时间内得出结果。在我们的调研选型过程中发现了Apache Kylin这一基于预计算思想实现的海量数据分布式预处理引擎,它的一个亮点就是可以实现超大数据集的亚秒级查询。
经过初步的数据模拟测试,我们发现Kylin确实可以在1秒内反馈十亿数据量的聚合查询结果,很好地满足了我们的业务需求。但是测试并没有到此为止,我们展示给客户的报表页面包含了15张图表,每一张图表的展示BI系统都会异步的发送REST API请求到Kylin查询数据,基于产线规模分析,如果短时间内有20个客户(这个数据很保守)在单节点上同时查询报表,会触发15*20 = 300个请求,那么Kylin在短时间内的并发响应性能就是我们需要测试的对象。
前提
为了降低网络开销对并发性能测试结果的影响,我们将并发测试工具与Kylin部署在相同的网络环境内。
测试工具
除了选用传统的压力测试工具Apache JMeter外,我们还使用了另一款开源工具Gatlin (https://gatling.io/) 测试相同的用例,对比排除测试工具的影响。
测试策略
通过累加并发线程数来模拟不同量级的用户请求,观察60秒内平均响应时间,确定Kylin的并发响应瓶颈,同时也需要观察最大响应时间和成功率。为了确保不被缓存影响,整个测试我们都关闭了Kylin的query cache,确保每个查询都被发送到底层执行。
测试结果
根据结果绘出趋势图:
测试结论
当并发数达到75时,Kylin的查询响应数达到峰值90,即使进一步提高并发数,单秒的查询响应数也并没有提高。单个节点每秒90的并发查询响应数只能满足此场景中90/15=6个客户同时查询报表,考虑到集群内Kylin query node的数量为3,每秒18个客户的查询能力也远远不能满足我们的业务需求。
通过对Kylin Query模块代码的阅读和分析,我们了解到Kylin的查询是通过启动HBase Coprocessor在HBase的region server中并行执行过滤和计算。基于这个信息我们最初排查了测试环境HBase集群的资源使用情况,观察后发现高并发请求发生时,region server上处理的RPC Task数量并没有与Kylin查询请求数成线性增长,于是初步定位问题应该出在Kylin端,可能存在线程阻塞。
我们选用了火焰图和JProfile对Kylin Query server进行了数据收集分析,结果都不是很理想,没有定位到问题的源头。之后我们尝试通过jstack抓取Kylin的线程快照,分析jstack log后我们最终发现了造成并发查询瓶颈问题的原因。这里用其中一次测试的结果举个例子(Kylin 版本 2.5.0)。
在一次快照中一个线程lock在sun.misc.URLClassPath.getNextLoader。此线程的 TID 是0x000000048007a180:
"Query e9c44a2d-6226-ff3b-f984-ce8489107d79-3425" #3425 daemon prio=5 os_prio=0 tid=0x000000000472b000 nid=0x1433 waiting }}{{for monitor entry [}}\\\{{0x00007f272e40d000}}{{] java.lang.Thread.State: BLOCKED (on object monitor) at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:469) - locked <0x000000048007a180> (a sun.misc.URLClassPath) at sun.misc.URLClassPath.findResource(URLClassPath.java:214) at java.net.URLClassLoader$2.run(URLClassLoader.java:569) at java.net.URLClassLoader$2.run(URLClassLoader.java:567) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findResource(URLClassLoader.java:566) at java.lang.ClassLoader.getResource(ClassLoader.java:1096) at java.lang.ClassLoader.getResource(ClassLoader.java:1091) at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1666) at org.apache.kylin.common.KylinConfig.buildSiteOrderedProps(KylinConfig.java:338)
同一时刻有43 个其它线程waiting to lock <0x000000048007a180>
"Query f1f0bbec-a3f7-04b2-1ac6-fd3e03a0232d-4002" #4002 daemon prio=5 os_prio=0 tid=0x00007f27e71e7800 nid=0x1676 waiting }}{{for monitor entry [}}\\\{{0x00007f279f503000}}{{] java.lang.Thread.State: BLOCKED (on object monitor) at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:469) - waiting to lock <0x000000048007a180> (a sun.misc.URLClassPath) at sun.misc.URLClassPath.findResource(URLClassPath.java:214) at java.net.URLClassLoader$2.run(URLClassLoader.java:569) at java.net.URLClassLoader$2.run(URLClassLoader.java:567) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findResource(URLClassLoader.java:566) at java.lang.ClassLoader.getResource(ClassLoader.java:1096) at java.lang.ClassLoader.getResource(ClassLoader.java:1091) at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1666) at org.apache.kylin.common.KylinConfig.buildSiteOrderedProps(KylinConfig.java:338)
分析代码栈我们可以追溯到最近的Kylin的逻辑在org.apache.kylin.common.KylinConfig.buildSiteOrderedProps(KylinConfig.java:338),然后再结合Kylin源代码进一步分析,成功就离我们不远了。
当
Kylin query engine 构建查询请求时, 会导出Kylin properties (Kylin里的各种配置)发送给HBase Coprocessor,在KylinConfig.class中有这么一个方法:
function private static OrderedProperties buildSiteOrderedProps()
它的执行逻辑是这样的:
1. 对于每个线程, 会调用getResouce 去读取"kylin-defaults.properties"(默认配置文件,用户不可修改) 的内容。
// 1. load default configurations from classpath. // we have a kylin-defaults.properties in kylin/core-common/src/main/resources URL resource = Thread.currentThread().getContextClassLoader().getResource("kylin-defaults.properties"); Preconditions.checkNotNull(resource); logger.info("Loading kylin-defaults.properties from {}", resource.getPath()); OrderedProperties orderedProperties = new OrderedProperties(); loadPropertiesFromInputStream(resource.openStream(), orderedProperties);
2. 循环10次去读取"kylin-defaults" +(i)+ ".properties", 线程阻塞就发生在这里。
for (int i = 0; i < 10; i++) { String fileName = "kylin-defaults" + + ".properties"; URL additionalResource = Thread.currentThread().getContextClassLoader().getResource(fileName); if (additionalResource != null) { logger.info("Loading {} from {} ", fileName, additionalResource.getPath()); loadPropertiesFromInputStream(additionalResource.openStream(), orderedProperties); }
通过版本追溯,这段逻辑是在2017/6/7 引入的,对应的JIRA ID 是KYLIN-2659。
针对第一段逻辑,因为kylin-defaults.properties是打包在kylin-core-common-xxxx.jar中,在Kylin启动后是不会改变的,因此不需要每次查询时都从文件读取。可以将这段逻辑挪至 getInstanceFromEnv(),这个静态方法只会在服务加载时调用一次。
在修改这块逻辑时遇到一个坑。在Coprocessor中的类CubeVisitService,它会调用KylinConfig作为工具类去生成KylinConfig 对象,引入读取properties文件的逻辑是危险的,因为 Coprocessor中没有打包kylin.properties文件。
buildDefaultOrderedProperties();
对于第二块逻辑,设计的最初应该是为了未来扩展,允许用户定于多达10个default properties文件(彼此覆盖),但是经历了一年半的版本迭代,这段逻辑似乎没有被使用。但是为了降低风险,在这次修复中暂时保留这段逻辑,因为前面的改动后,这段逻辑只会在服务加载时执行一次,因此它的时间损耗基本可以忽略。
基于修复后的版本在同样的数据量和环境中进行测试,结果如下:
同样地绘制出趋势图:
当并发数达到150时,Kylin每秒能处理的查询请求数可以达到467,与此bug修复前并发处理能力提高了5倍左右,趋势图也是呈线性增长的,可以看到瓶颈基本消除了。我们没有再进一步提高并发数测试的原因是Kylin Query engine都是做集群负载均衡配置,一味地增加单节点的并发连接数反而会增加Tomcat服务器的压力(Tomcat 默认最大线程数为150)。
重新收集分析jstack日志,再没有发现线程阻塞的问题。
根据现在的测试结果,单个Kylin节点每秒可以处理 467/15= 31个客户查询,是满足当前业务需求的。此外,如果开启Kylin的查询缓存,单节点 QPS 还可以提升若干倍,足以满足我们的需要。
Kylin的一大亮点就是提供亚秒级的海量数据集的查询,而实现这个目标既得益于Cube预计算的设计,以及Query时Apache Calcite算子的优化,同时在2.5.0版本中也引入了PreStatement Cache来减少Calcite语义解析的消耗。每一点的查询性能优化都是来之不易的,在引入新功能、bug fix等代码改动的时候,大家要额外注意这些改动对 Kylin query engine的影响,有时可能会牵一发而动全身。这些在高并发下的问题,往往是比较难重现和分析的。
另外,查询性能测试不能仅局限在单次或少量查询,可以结合实际业务需求估算并发请求数做相应的高并发性能测试。对于企业级的报表系统,客户的新页面载入忍耐度在3秒钟,这包括了页面渲染和网络消耗,所以后台数据服务的查询响应最好控制在1秒以内。这在基于大数据集的业务场景下确实是不小的挑战,Kylin则很好的满足了这一需求。
目前这个问题已经作为KYLIN-3672在JIRA上提交,并在Kylin 2.5.2版本发布,感谢这一过程中来自Kyligence团队史少锋同学的帮助。
参考文献:
【1】https://issues.apache.org/jira/browse/KYLIN-3672
01 现象 社区小伙伴最近在为 Kylin 4 开发 Soft Affinity + Local Cache
01 背景 随着顺丰末端物流(末端物流主要分为对小哥、柜机、区域等的资源的管理和分批;对路径、排班、改派等信息
Apache Kylin 的今天 目前,Apache Kylin 的最新发布版本是 4.0.1。Apache
Kylin 入选《上海市重点领域(金融类)“十四五”紧缺人才开发目录》 数字经济已成为全球增长新动
在 Kyligence 主办的 Data & Cloud Summit 2021 行业峰会的「数字化转
近日由 Kyligence 主办的 Data & Cloud Summit 2021 行业峰会在上海成
近五年来,Kyligence 服务了金融、制造、零售、互联网等各个行业的龙头企业,我们在服务这些企业的过程中,
2021年1月14日,Kyligence 产品经理陈思捷开启了我们在 2021 年的首场线上分享,为大家介绍了
400 8658 757
工作日:10:00 - 18:00
已有账号? 点此登陆
预约演示,您将获得
完整的产品体验
从数据导入、建模到分析的全流程操作演示。
行业专家解惑
与资深行业专家的交流机会,解答您的个性化问题。
请填写真实信息,我们会在 1-2 个工作日内电话与您联系。
全行业落地场景演示
涵盖金融、零售、餐饮、医药、制造等多个行业,最贴合您的业务需求与场景。
Data + AI 应用落地咨询
与资深技术专家深入交流,助您的企业快速落地 AI 场景应用。
立即预约,您将获得
精准数据计算能力:
接入高精度数值计算大模型服务,为您的企业级AI应用提供强大支持。
个性化业务场景解决方案:
量身定制的计算模型和数据分析服务,切实贴合您的业务需求和应用场景。
Data + AI 落地应用咨询:
与资深专家深入探讨数据和 AI 如何帮助您的企业加速实现应用落地,构建更智能的数据驱动未来。
申请体验,您将获得
体验数据处理性能 2x 加速
同等规模资源、同等量级数据、同一套数据处理逻辑,处理耗时下降一半
专家支持
试用部署、生成数据、性能对比各操作环节在线支持