乐趣区

关于数据库:当高并发来袭StarRocks-Query-Cache-一招搞定

您是否已经遇到这样的状况?每天早上或业务流动高峰期,大量用户涌入报表平台或数据利用,心愿查看特定业务畛域的最新指标或趋势。这些用户可能会基于宏大的数据集进行大量相似的聚合查问,造成集群的 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_…

退出移动版