您是否已经遇到这样的状况?每天早上或业务流动高峰期,大量用户涌入报表平台或数据利用,心愿查看特定业务畛域的最新指标或趋势。这些用户可能会基于宏大的数据集进行大量相似的聚合查问,造成集群的 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 Cache
set enable_query_cache=true;
-- 因为只有 1 正本,因而调整 pipeline dop 为 1
set pipeline_dop=1;
-- 关上 Query Profile
set 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_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;
执行后咱们查看 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 fingerprint
FROM
(
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_…