您是否已经遇到这样的状况?每天早上或业务流动高峰期,大量用户涌入报表平台或数据利用,心愿查看特定业务畛域的最新指标或趋势。这些用户可能会基于宏大的数据集进行大量相似的聚合查问,造成集群的 CPU 负载继续攀升,从而导致查问性能一直下滑。
针对这种高并发且出现肯定法则的查问,是否存在一种办法能够让集群在解决时智能地“精简计算量”呢?

1、StarRocks Query Cache(查问缓存)

为了解决这一问题, StarRocks 研发了 Query Cache(查问缓存)。它的作用是将本地聚合的两头后果缓存在内存中,以供后续复用。 当执行查问时,StarRocks 会优先查看 Query Cache。如果发现雷同查问语义的后果曾经存在于缓存中,就能够间接复用这些两头后果,防止反复计算,从而节俭了磁盘拜访和局部计算开销,无效晋升查问性能。

值得注意的是,Query Cache 并不是 Result Cache,它缓存的是查问过程中的聚合两头后果而不是最终后果, 因而大大晋升了缓存的命中率。即使对于不完全一致的查问,也能起到减速作用。据测试结果显示,在高并发场景下,Query Cache 能够将查问效率进步 3 至 17 倍, 从而无效加重集群的负载压力,提供更疾速的查问响应工夫,使得整个零碎在高峰期仍然可能放弃高性能运行。


(Query Cache 机制)

2、面向更多场景设计,最大限度晋升缓存复用率

StarRocks 的 Query Cache 在设计时就思考了如何可能让缓存的信息最大水平失去复用。整体来讲,下列三个场景均能够利用到 Query Cache:

  • 语义等价的查问
  • 扫描分区重合的查问:基于谓词的查问拆分
  • 仅波及追加写入(无删除及更新)数据的查问:多版本缓存能力

(1)语义等价的查问


相似上图的例子,左图的子查问与右图在语义上是等价的,因而在执行了其中一个后,另一个查问就能够复用缓存中的后果减速查问。

语义等价还蕴含十分多的场景,更多例子请见:(https://docs.starrocks.io/zh-cn/latest/using_starrocks/query_cache)#语义等价的查问

(2)扫描分区重合的查问:基于谓词的查问拆分

在上图的两个查问中,ts 是分区列,查问仅在分区列的筛选区间上有区别,并且其中一部分区间是重叠的。在执行任意查问时,StarRocks 会将谓词中的区间依照分区来切割,并依照分区级别缓存聚合两头后果。在下次执行时,就能够复用有重叠的分区后果,达到查问减速的成果。

更多例子请见:
https://docs.starrocks.io/zh-cn/latest/using_starrocks/query_cache#扫描分区重合的查问

(3)仅波及追加写入数据的查问:多版本缓存能力

除了上述在不同查问中尽可能复用 Cache,还有一类场景须要思考:如果数据变动了该如何应答?Query Cache 能够在只有追加写入(append)的场景下被复用。

总体来说,随着数据导入,Tablet 会产生新的版本,进而导致 Query Cache 中缓存后果的 Tablet 版本落后于理论的 Tablet 版本。这时候,多版本 Cache 机制会尝试把 Query Cache 中缓存的后果与磁盘上存储的增量数据合并,确保新查问可能获取到最新版本的 Tablet 数据。

更多例子请见:https://docs.starrocks.io/zh-cn/latest/using_starrocks/query_cache#仅波及追加写入数据的查问

3、在这些场景上,Query Cache 能事倍功半

依据下面的解说,能够看出相比基于后果的 Result Cache,基于聚合两头后果的 Query Cache 可能被更大程度地利用。因此 Query Cache 就更实用于以下的查问场景:

  • 聚合类查问执行比拟频繁,蕴含针对宽表的聚合查问与星型模型 JOIN 后的聚合查问
  • 两个语言类似的查问,但容许不完全相同
  • 数据只会追加写入,没有更新操作

这样的查问特色在很多场景中都很常见,例如:

  • 监控或报表平台: 数据集会随着工夫的推移逐步减少,而且用户会对不同时间段的数据汇总后果感兴趣
  • 面向用户的高并发剖析: 蕴含依照特定维度指标进行汇总的查问

在这些场景中,Query Cache 能够通过重复使用查问的两头后果,防止反复计算,放慢查问的响应速度。同时,因为缓存机制的应用,零碎的可扩展性也失去了晋升,从而能够更好地解决高并发的查问申请,为用户提供更好的体验。

4、最佳实际

为了更高效地利用 Query Cache,建表时须要依据查问设置正当的分区策略,并抉择适合的数据分布形式, 包含:

  • 抉择一个独自的 date/datetime 类型的列为分区列。 这个列的数据最好随着导入枯燥减少,并且查问会基于该列进行区间筛选。
  • 抉择适合的分区大小。 因为随着导入,最近的分区数据很有可能会常常变动,从而导致缓存生效。因而过大或过小的分区都会影响缓存的命中率。
  • 确保分桶数量在数十个左右。 如果分桶数量过小,那么当 BE 须要解决的 Tablet 数量小于 pipeline_dop 参数的取值时,Query Cache 无奈失效。

并且,因为每个 BE 节点在内存中保护本人的本地缓存,只有 BE 节点上有查问所需的正本数据,查问就能够被调配给该 BE。所以,为了可能最大水平地利用到 Cache,查问应该至多执行与正本数(replication_num)雷同的次数。不过,Query Cache 也并不是只有在齐全加载后才起作用。

5、如何应用 Query Cache

在这一节咱们将用通过一个简略的例子来展现 StarRocks Query Cache 是如何工作的。

(1)筹备工作

Query Cache 默认状况下是禁用的。您能够通过会话变量来启用它。 在例子中咱们在单个 BE 集群中创立一副本的表,为了使 Query Cache 可能发挥作用,也须要对 pipeline_dop 进行调整。为了确认 Query Cache 的应用状况,还须要关上 Profile。

--关上 Query Cacheset enable_query_cache=true;--因为只有1正本,因而调整 pipeline dop 为1set pipeline_dop=1;--关上 Query Profileset is_report_success = true;set enable_profile = true;
建表和导入语句请见:https://docs.starrocks.io/zh-cn/3.1/using_starrocks/query_cache#数据集

(2)示例查问

接下来咱们将用一个简略的例子来激活 Query Cache 并查看它的应用状况。
首先咱们执行第一个根底查问:

-- Q1: 根底查问SELECT    date_trunc('hour', ts) AS hour,    k0,    sum(v1) AS __c_0FROM    t0WHERE    ts between '2022-01-03 00:00:00'    and '2022-01-03 23:59:59'GROUP BY    date_trunc('hour', ts),    k0;

执行后咱们查看 BE 的缓存状况。其usage相干指标被填充,阐明 Query Cache 曾经被填充:

curl http://127.0.0.1:8040/api/query_cache/stat{    "capacity": 536870912,    "usage": 3889,    "usage_ratio": 0.000007243826985359192,    "lookup_count": 42,    "hit_count": 0,    "hit_ratio": 0.0 

接下来执行语义等价的查问:

-- Q2: 语义等价的查问SELECT    (        ifnull(sum(murmur_hash3_32(hour)), 0) + ifnull(sum(murmur_hash3_32(k0)), 0) + ifnull(sum(murmur_hash3_32(__c_0)), 0)    ) AS fingerprintFROM    (        SELECT            date_trunc('hour', ts) AS hour,            k0,            sum(v1) AS __c_0        FROM            t0        WHERE            ts between '2022-01-03 00:00:00'            and '2022-01-03 23:59:59'        GROUP BY            date_trunc('hour', ts),            k0    ) AS t;

执行后咱们持续查看 BE 的缓存状况。这里能够看到,Query Cache 被命中:

curl http://127.0.0.1:8040/api/query_cache/stat{    "capacity": 536870912,    "usage": 3889,    "usage_ratio": 0.000007243826985359192,    "lookup_count": 44,    "hit_count": 2,    "hit_ratio": 0.045454545454545459

进一步剖析此次查问的 Profile。能够发现 Profile 中呈现 Cache 节点,Populate 相干指标均为 0,阐明没有新的聚合后果被缓存;并且 Scan 节点的 RawRowsRead 指标为 0,阐明理论并没有读取数据:

-- Cache节点populate相干指标均为0- CachePopulateBytes: 0.00 - CachePopulateChunkNum: 0- CachePopulateRowNum: 0- CachePopulateTabletNum: 0-- Scan节点RawRowsRead为0- RawRowsRead: 0M (0)

6、性能报告

只管 StarRocks 的 Query Cache 不是 Result Cache,然而反复利用两头计算结果依然能够带来很大的性能晋升。这不仅实用于聚合查问,还能减速 JOIN 操作。当初让咱们来看一些性能数据。为简略起见,咱们将后果示意为 RT 比率,即查问提早的 no_cache/cache_hit 比率。

留神,下方所有测试中 Query Cache 均曾经被充沛加载。

(1)宽表测试

硬件3 x (CPU: 16cores, 内存: 64GB)
数据集SSB 100GB 宽表
并发量10


(Query Cache vs. 冷查问)

能够看到,在 10 并发的单表聚合查问中,Query Cache 命中能够带来高达 10 倍的性能晋升。

(2)星型模型测试

硬件3 x (CPU: 16cores, 内存: 64GB)
数据集SSB 100GB 多表
并发量10

能够看到,在 10 并发的多表聚合查问中,Query Cache 命中能够带来高达 17 倍的性能晋升。

7、总结

Query Cache 能够极大地晋升聚合查问的性能。通过将本地聚合的两头后果存储在内存中,Query Cache 能够防止对相似于先前查问的新查问进行不必要的磁盘拜访和计算。Query Cache 还能够解决不完全相同的查问和数据,这使得它比 Result Cache 更加灵便。在高并发场景中,许多用户在大型简单数据集上运行相似的查问时,Query Cache 尤其有用。借助 Query Cache,StarRocks 能够为聚合查问提供疾速而精确的后果,节省时间和资源,并实现更好的可扩展性。

Query Cache 探讨专区
为了帮忙用户更好的应用 query cache,社区在论坛上开了一个相干的探讨帖,欢送来分享你们都是怎么应用 query cache,或是应用过程中遇到了什么问题。性能晋升的招式,大家都学起来!https://forum.mirrorship.cn/t/topic/8468

参考资料
https://docs.starrocks.io/zh-cn/latest/using_starrocks/query_...