即席查询(Ad Hoc)如何做到又快又稳?
数字化与数字生态建设,是当前所有企业成长发展的必经之路。随着“加强新型基础设施建设”第一次被写入政府工作报告,5G、人工智能、工业互联网、智慧城市等新型基建彻底激发了数字的价值。
不过与数字世界蓬勃发展伴生而来的,是以指数形态爆炸增长的数据体量。在新基建中扮演重要角色的 5G、物联网、区块链等技术也蕴藏着丰富的诸如人、设备、车辆等流动变化且相互关联的数据,使得数据的来源、种类、结构、关联等因素都变得更为复杂,这也为数据分析的工作增加了不少难度。
并且在数据体量增长和数据种类丰富的同时,互联网应用对于数据分析实时性的要求也变得越来越高,尤其是在 5G 的加持下,越来越深的链接以及越来越快的触达速度,无一例外都在考验着企业决策的正确与否。在这样一个追求快+效率的时代,留给企业试错的空间正在越来越小。
因此需要依照不断变化的数据来做出实时精准的商业决策,需要从这些串联的数据中挖掘出有价值的信息,需要提前设定好与自身业务关系紧密的各种指标,这也意味着需要底层架构具备强大的数据存储以及分析计算能力,需要这些能力来满足实时变化的数据分析需求以赋能企业业务的目标。这就对企业的大数据平台提出了更高的要求。
然而当下数据之间包含大量节点,海量数据的来源可能是经过数十亿次的模拟、实验设备、互联网、应用等。对企业来说,需要把多个源头的数据进行整合,这就需要企业建立新的计算平台架构、从0开始建立数据分析模型并引入新的处理算法和索引技术,这无疑对开发者的技术能力提出了相当大的挑战。此外不只是技术者,业务分析和运营人员在这样一个快速变化的时代,也需要得到来自于数据的实时反馈。
因此,使用更加灵活的数据分析技术来为业务赋能正是突破业务十字路口的关键之举。通常来说,一般的数据分析能力就已经能够有效解决当下行业对于复杂关系数据分析的需求,然而这种对于实时性、灵活性需求极高的数据分析能力,即席查询无疑是更合适的那一个。
然而即便使用即席查询也不代表着一劳永逸,在应用即席查询的业务场景中,往往会出现各种各样的问题导致性能缓慢。秉着「让数据能力平民化」的使命,关于即席查询能力的场景化难题,易观数科也有着自己的思考。
即席查询也就是自定义多维查询,但是在建立大数据自定义多维查询过程当中,往往会遇到各种各样的问题:
只查询单个总 PV 和总 UV,但是却读取了上百 G 数据;
虽然 CPU 还没跑满,但是内存一直不够,各种 OOM;
CPU、内存、磁盘 IO 都空闲,但是查询性能就是慢;
晚上跑 ETL 集群资源足够,白天分析师互相杀 SQL。
上述的这四种问题虽然都是在即席查询场景中相对常见的问题,但解决起来却并不容易。
易观数科围绕上述的这些痛点,成功构建了商业级别 Ad-hoc 查询引擎。基于用户行为分析产品易观方舟的经验,通过"减 IO、控内存、降带宽、优调度"这四个手段切实解决「即席查询 Ad Hoc」的上述相关难题。
一、减 IO
减 IO 是一个统称,是指在查询的每个环节中,都需尽量去减少向上一步传输的数据量。
场景1
只读取相关数据
以下表为例,分别从表中读取 xwhat、xwho、xwhen 这几列数据。
在减少 IO 的过程中,可以看见由于使用了 orcfile 这种列式存储的方式,能够轻松的把 ProjectNode 下推到 TableScanNode 节点,不需要读取过多的无用数据,仅仅读取需要的几列数据,从而起到减少数据从磁盘到内存 IO 的量。
场景2
建立稀疏索引
以下图为例,依然是从表中分别读取 xwhat、xwho、xwhen 这几列数据,并将 xwho="用户1" 作为这一行为的事件数据。
在该场景下,通过继续上面的动作,由于这部分额外增加了 xwho 的属性过滤,所以可以在存储数据时对 xwho 进行排序,并建立稀疏索引,尽可能的在 TableScanNode 时就利用有序索引+稀疏索引把数据过滤掉,进一步减少数据向上一节点传输的体量。
场景3
易观方舟的减 IO 方式
在易观方舟实际的转换漏斗模型中,需要采用多种减 IO 的措施。
二、控内存
上面提到了需要尽可能减少数据进入计算引擎内存的量,但是往往随着业务的发展,依然会面临硬件资源不足的情况出现。例如易观方舟就是一款私有化部署的智能用户数据中台,就经常会需要在有限的资源下满足客户多种的数据分析需求的挑战。
场景1
分桶执行策略
这里以一个场景为例,假设需要处理超过1个月的行为数据,预计内存使用 30G。但是当前用户单台硬件分配给秒算引擎的可用内存只有 10G,很明显此时硬件资源是无法满足业务查询需求的。
面对上述场景,这时就需要一个更优的执行策略--Bucekt Execution,也被称作分桶执行策略:优化后的内存占用=原内存占用/数据分桶个数。
通过把 30G 分为5个桶来执行,套用公式以后:优化后的内存占用只需要 6G。
场景2
流量洪峰时的策略执行
分桶执行策略可以在数据稳定的情况下使用,但是面对诸如618,双11等特殊时间节点下的流量爆点,数据往往会出现 N 倍变化的情况,此时上个场景中所提到的『分桶执行策略』就不太合适了,因为此时研发人员不清楚具体流量峰值,因此无法进行合理的物理分桶。如果对物理分桶过多,往往会造成小文件太多导致 HDFS 的 IO 性能变慢。
面对这个场景,就需要一个更为灵活的执行策略--Dynamic Bucekt Execution,即动态分桶执行策略:优化后的内存占用=原内存占用/数据分桶个数/用户 ID 分片数。
在动态分桶的基础上,优先保证每个桶的主键全局有序,再按照主键进一步进行范围切割。在这个场景案例中,只需要把每个桶的用户再细分为3份,这样总内存使用就只需要 2G 内存。
三、降带宽
通过以上2步,就已经可以很好地实现『减 IO、控内存』的目标了。但是在大数据场景中,影响效率的并非只有上文所提到的这两个因素,集群之间的网络带宽情况经常也会成为导致查询性能降低的诱因之一。
因此这部分的重点是降低带宽。通过把用户数据进行 hash 并分成多片,使每台机器只处理特定数据,这样就不会涉及到计算中间结果的再次 shuffle。
可参照下图,在使用该特性之前,所有的数据计算中间结果集 shuffle 到每个节点再次计算,这样会造成巨大的传输数据量;在使用该特性之后,网络传输数据量从 2.41GB 降低 68.71MB,降低了35倍,同时 CPU 执行时间也随之降低。
四、优调度
即便通过上述『减 IO、控内存、降带宽』这3个环节的性能优化后,在实际数据处理的过程中往往还是会遇到集群压力负载大、多用户同时查询等场景下的不可用情况。
此时就需要进一步梳理客户场景对 ad-hoc 查询的需求是什么,一般来说,有以下三点:
查询结果确定可以出结果,而不是直接报错和多次人工重试;
在多人使用的场景下,分析师希望自己先提交的查询一定能先出结果,而不是被后面的查询抢占资源;
日常数据分析过程中,有一些紧急查询需要提前,不能等待其它任务完成。
通过以上一些场景需求,从而可以针对性定义了3个优化目标,分别为:查询结果可保证、查询速度可预期以及查询队列可控制。
目标1
查询结果可保证
具体流程可参见下图:
目标2
查询速度可预期
用户查询进入队列并行计算以后,有2个痛点需要解决,分别为先提交的查询先出结果确保不被大查询占用所有资源。针对这两个痛点,执行策略可以基于使用场景来调整:
FCFS 调度算法(First-Come,First-Served Scheduling),通常 FCFS 调度算法适应性最好,客户查询都遵循谁先提交查询,谁先出结果;
RR 轮转算法法(Round Robin,RR),该算法绝对公平,所有并发查询都会得到公平的资源;
针对以上这2种调度策略,通常在白天客户使用情况下建议使用 FCFS 调度,这样能够保证及时性。在夜间跑离线任务时,RR 调度能够确保资源的平均分配。
目标3
查询队列可控制
在实际场景中,并不是所有机器给出的策略都是最好的,所以易观方舟提供了可以人工调整队列的工具--插队模式"BOSS 队列"。同时配合 FCFS 调度算法,可以确保即便在高并发场景下,高优先级查询也能够优先在第一时间出结果。
优化结果
通过以上4步的持续迭代,也推动了方舟5.1版本的发布,并在内部模拟的多种查询场景中,为多个模块带来了数倍的性能提升。
最后
开源一直是易观数科所努力和实践的方向,易观也积极拥抱 Apache 社区,所用的组件基于完全 Apache license,实现了源码的自我可控;
易观数科也一直坚持【从社区中来,到社区中去】的工作方法论,易观数科已经把 kudu connector 完整实现了 Bucket Execution 的特性并反馈到了 PrestoSQL (近期更名为 Trino)社区,期待能够与社区共同成长。
最后易观数科为让整个数据处理有更快的数据分析速度,已经连续办有四届 OLAP 算法大赛,每年的 5、6月份开始报名,欢迎感兴趣的小伙伴关注哈,
为促进大数据行业的发展,也已免费开放支持私有化部署的易观方舟单机版 - Argo,欢迎下载试用。
同时我们也组织有 Presto、Clickhouse 、Alluxio 等大数据开源技术交流群,感兴趣的伙伴,欢迎关注本公众号后,回复“加群”,友情帮拉
你“在看”我吗?