正文
1)从用户体验角度:改善查询性能,提升查询效率和稳定性;
2)从集群维护角度:提升集群稳定性,增强查询结果复用能力,提高算力使用效率。
数据报表平台执行查询的主要链路如图1所示,其中有几个关键构件:
图1:Nova 数据查询链路
1)Nova:应用本体,提供可视化用户界面,包含报表即时查询、执行离线定时任务等功能;
2)Router:
用于分离指向不同引擎的查询请求,起到SQL路由功能;
3)Starrocks & Hive:平台使用Starrocks作为主要查询引擎,向Hive外表发起查询请求。
在硬件资源有限的情况下,要提升查询性能,最直观的思想是对重复的查询进行结果复用。在对平台的查询请求数据进行统计分析后,可发现存在相当数量的查询请求在不同时段内重复出现,这为我们引入缓存机制提供了实践基础。
若将在执行过程中可能遭遇瓶颈的查询进行划分,可将大致分为I/O型、计算型和高频型三类,其中I/O型查询对网络和磁盘带宽的要求较高,往往涉及大规模数据的扫描;计算型查询对CPU和内存资源的要求较高,往往涉及大量连接、分组、聚合、筛选、再计算操作;高频型查询的单次调用开销可能较小,但在单位时间内发起的次数显著高于均值,在涉及远程调用(如元数据获取)的环节可能遭遇性能瓶颈,且在单位时间造成的资源开销可能与大查询相当。
图2:受限查询分类
目前,在整个数据查询链路中,我们在以下几个环节引入了缓存机制,以应对不同类型查询所带来的挑战。
当Starrocks从Hive外表进行数据查询时,Scan算子会将所需数据文件以块的形式读取至本地。对于典型的I/O型查询而言,这个过程所需时间可达整个查询流程耗时的70%以上。在业务高峰期,由于大量查询请求同时发起,I/O型查询的堆积将导致其他查询请求读取数据文件的等待时间增长,进而影响查询响应时间。
针对这类情况,我们在Starrocks集群中开启了Data Cache,将每次读取得到的文件块标识并临时存储在本地磁盘中,在下次查询请求需要相同文件块时,若发现该文件块没有更新,则直接从本地磁盘读取,避免了经由网络和Hive带来的文件读取延迟。
通过Data Cache缓存的文件块在Starrocks中由带冷热分区的LRU队列维护,当队列满时,将根据文件块的访问频率和时间戳进行淘汰,以保证缓存的命中率。
从缓存一致性角度,Starrocks在使用Data Cache时,会通过元数据判断底表数据是否发生更新,若发现数据文件已更新,则将废弃缓存数据,重新拉取底表数据文件,以保证查询结果的准确性。
通过对查询请求命中底表的情况进行统计,可发现其中热点表的使用呈现一定的规律性(如:每日相近时刻、每周固定几日访问量达峰等)。为此,我们为统计得到的各热点表建立了用户画像,记录并预测其访问高峰。
图3:预热机制
通过在业务高峰到来前将热点表数据主动Cache预热,可进一步分散业务高峰期的I/O压力。如图4 所示,这部分主动指定Cache的数据文件将会优先被置入LRU队列的热区,以保证其在高峰期的查询中能够被快速命中。
图4:Data Cache LRU 队列
在Starrocks查询引擎执行查询时,需要获取Hive表的元数据信息,如表的列信息、分区信息、表的存储格式;HDFS File的元数据信息,如block块属性等。Starrocks将通过这些信息来生成最优的执行计划。在业务高峰期,大量并发查询可能导致Hadoop Namenode的元数据请求压力过大,进而影响查询的执行效率。
Starrocks原有的元数据缓存时间较短,这是因为其无法实时感知HDFS File文件变化。为防止缓存不一致,原有的Remote File元数据缓存时间不宜设置过长,但这会导致即使元数据未更新,在某些场景下Starrocks也会频繁发起重复的元数据请求。
为此,我们选择在Starrocks的FE侧通过元数据接口(该接口调用开销远小于元数据的获取)对元数据的新鲜度进行检测,仅在远端元数据发生更新时拉取元数据,此功能可使得Remote File缓存时长延长至6小时,在保证缓存一致性的同时,提升相同元数据的复用程度。
当数据从查询引擎返回至Router时,Router会将查询结果进行缓存,以便后续面对完全相同的查询请求,可直接从缓存中获取结果,避免重复计算。
在缓存一致性方面,Router同样可通过血缘信息实时获取底表数据的更新时间,从而判断缓存数据是否过期。在缓存数据过期时,Router将弃用缓存数据,重新执行查询,以保证查询结果的准确性。
对于查得的报表数据,平台支持用户将数据下载至本地,以便用户进一步分析。在实践过程中我们发现,部分报表数据除了在查询后被即时下载外,还可能需要在未来的某个时间点被再次下载(如浏览器关闭后)。这种行为将触发二次查询,导致相同请求被反复执行以满足下载需求。
针对这种现象,我们在Download服务中同样引入了缓存机制,将下载的数据进行缓存,以便后续相同的下载请求直接从缓存中获取数据。
图5:Download 缓存
如图6所示,通过引入多维度数据缓存机制,我们在平台的数据传输的全链路中,尽可能实现了对重复数据的复用。而为了进一步提升在计算过程中,数据和算力的使用效率,我们进一步在物化视图的使用上进行了探索。
图6:查询链路缓存总览
四、使用物化视图加速查询
物化视图(Materialized View, MV)作为一种预先计算的结果集,可以有效减少查询时的计算量,提升查询性能。面对计算型查询,MV可以将查询计算的部分结果进行固化存储,避免复杂计算逻辑的重复执行;面对I/O型查询,MV可以将查询所需数据进行预聚合,减少数据扫描的规模,或者更简单地,将需要频繁查询的数据底表保存为MV,作为优先级更高的Data Cache来使用,使得对Hive外表的查询达到和Starrocks内表一致的查询性能。不过,想要发挥MV的优势,需要解决如下几个问题: