diff --git a/Querying/groupby.md b/Querying/groupby.md index f878fcb..759c720 100644 --- a/Querying/groupby.md +++ b/Querying/groupby.md @@ -193,8 +193,42 @@ GroupBy查询可以按多值维度分组。在多值维度上分组时,来自 ### 详细实现 #### 策略 + +GroupBy查询可以使用两种不同的策略执行。默认策略由Broker上的"druid.query.groupBy.defaultStrategy"运行时属性来决定,也可以在查询上下文中使用"groupByStrategy"重写。如果上下文字段和属性都未设置,则将使用"v2"策略。 + +* 默认设置为"v2",旨在提供更好的性能和内存管理。此策略使用完全堆外映射生成每段结果。数据处理使用完全堆外并发事实映射和堆内字符串字典合并每个段的结果, 这可能包括溢出到磁盘。数据进程将已排序的结果返回给Broker,Broker使用N-way来合并已合并的结果流。Broker在必要时将结果具体化(例如,如果查询对列而不是维度进行排序)。否则,在合并结果时,它会将结果流式返回 +* "v1"是一个遗留引擎,它使用一个部分在堆上(维度键和映射本身)和部分在堆外(聚合值)的映射在数据处理(Historical、Realtime、MiddleManager)上生成每段结果。数据处理然后使用Druid的索引机制合并每个片段的结果。默认情况下,此合并是多线程的,但也可以是单线程的。Broker再次使用Druid的索引机制合并最终结果集,Broker合并总是单线程的。因为Broker使用索引机制合并结果,所以它必须在返回任何结果之前具体化完整的结果集。在数据进程和Broker上,默认情况下合并索引完全在堆上,但它可以选择将聚合值存储在堆外。 + #### v1和v2之间的差别 + +两个引擎之间的查询API和结果是兼容的;但是,从集群配置的角度来看,有一些不同: + +* groupBy v1使用基于行的限制(maxResults)控制资源使用,而groupBy v2使用基于字节的限制。此外,groupBy v1在堆上合并结果,而groupBy v2在堆外合并结果。这些因素意味着内存调优和资源限制在v1和v2之间表现不同。特别是,由于这一点,一些可以在一个引擎中成功完成的查询可能会超出资源限制,并在另一个引擎中失败。有关详细信息,请参阅[内存调整和资源限制](#内存优化与资源限制)部分。 +* groupBy v1对并发运行的查询数量没有限制,而groupBy v2通过使用有限大小的合并缓冲池来控制内存使用。默认情况下,合并缓冲区的数量是处理线程数的1/4。您可以根据需要进行调整,以平衡并发性和内存使用。 +* groupBy v1支持在Broker或Historical进程上进行缓存,而groupBy v2只支持对Historical进程进行缓存。 +* groupBy v2支持基于数组的聚合和基于哈希的聚合。仅当分组键是单个索引字符串列时,才使用基于数组的聚合。在基于数组的聚合中,使用字典编码的值作为索引,这样就可以直接访问数组中的聚合值,而无需基于哈希查找桶。 + #### 内存优化与资源限制 + +当使用groupBy v2版本时候,通过三个参数来控制资源使用和限制: + +* `druid.processing.buffer.sizeBytes`, 每个查询用于聚合的堆外哈希表的大小(以字节为单位), 一次最多创建`druid.processing.numMergeBuffers`个哈希表,这也是并发运行的groupBy查询数量的上限。 +* `druid.query.groupBy.maxMergingDictionarySize`, 对每个查询的字符串进行分组时使用的堆上字典的大小(以字节为单位)。注意,这是基于对字典大小的粗略估计,而不是实际大小。 +* `druid.query.groupBy.maxOnDiskStorage`:每个查询用于聚合的磁盘空间量(以字节为单位)。默认情况下,这是0,这意味着聚合将不使用磁盘。 + + +如果`maxOnDiskStorage`为0(默认值),则超出堆内字典限制或堆外聚合表限制的查询将失败,并出现"Resource limit exceeded"错误,说明超出的限制。 + +如果`maxOnDiskStorage`大于0,则超出内存限制的查询将开始使用磁盘进行聚合。在这种情况下,当堆内字典或堆外哈希表填满时,部分聚合的记录将被排序并刷新到磁盘。然后,两个内存中的结构都将被清除,以便进一步聚合。然后继续超过`maxOnDiskStorage`的查询将失败,并出现"Resource limit exceeded"错误,指示它们的磁盘空间不足。 + +对于groupBy v2,集群操作符应该确保堆外哈希表和堆内合并字典不会超过最大可能并发查询负载的可用内存(由`druid.processing.numMergeBuffers`控制)。有关直接内存使用(按Druid进程类型组织)的更多详细信息,请参阅[基本集群调优指南](../Operations/basicClusterTuning.md)。 + +Broker对基础的groupBy查询不需要合并缓冲区。包含子查询的查询(使用`query`数据源)需要一个合并缓冲区(如果有一个子查询),如果有多个嵌套子查询层,则需要两个合并缓冲区。包含[`subtotals`](#关于subtotalSpec)的查询需要一个合并缓冲区。它们可以相互堆叠:一个包含多层嵌套子查询的groupBy查询,也使用小计,将需要三个合并缓冲区。 + +Historical和摄取任务需要为每个groupBy查询提供一个合并缓冲区,除非启用了并行组合,在这种情况下,每个查询需要两个合并缓冲区。 + +使用groupBy v1时,所有聚合都在堆上完成,资源限制通过参数`druid.query.groupBy.maxResults`来决定,这是对结果集中最大结果数的限制。超过此限制的查询将失败,并显示"Resource limit exceeded"错误,指示它们超出了行限制。集群操作应该确保堆上聚合不会超过预期并发查询负载的可用JVM堆空间。 + #### v2版本的性能优化 #### 备选方案 #### 嵌套的GroupBy查询