Hey, we occasionally seeing `Not enough merge buff...
# general
v
Hey, we occasionally seeing
Not enough merge buffer memory to execute this query.
when running GroupBy queries. Below is the example of one of those queries. To address the issue, we followed the suggestion provided in the error message: we added
druid.query.groupBy.maxOnDiskStorage=2gib
on all historicals, broker and middlemanager in addition to increased
druid.processing.buffer.sizeBytes=1gib
. We want to understand the root cause of the issue, and whether we mistuned our cluster or the query is poorly created (with respect to the schema). The query below is using
limitSpec
and we're returning only 5 records, but we're not sure where is that limit applied, on the broker or historical level. What's the recommendation would be when we encounter the error again? We seems cannot increase the buffer size beyond 2GiB of memory, and the only thing is left is to increase the spill on disk size, which affects the performance. Any insights/recommendations will be much appreciated
Copy code
{
  "queryType": "groupBy",
  "dataSource": {
    "type": "table",
    "name": "user"
  },
  "intervals": {
    "type": "LegacySegmentSpec",
    "intervals": [
      "2024-09-24T23:48:12.948Z/2024-10-01T23:48:12.948Z"
    ]
  },
  "filter": {
    "type": "and",
    "fields": [
      {
        "type": "not",
        "field": {
          "type": "selector",
          "dimension": "nativeIdPaths",
          "value": null
        }
      },
      {
        "type": "not",
        "field": {
          "type": "selector",
          "dimension": "pageId",
          "value": null
        }
      },
      {
        "type": "selector",
        "dimension": "pageIds",
        "value": null
      },
      {
        "type": "selector",
        "dimension": "customerId",
        "value": "<>"
      },
      {
        "type": "not",
        "field": {
          "type": "selector",
          "dimension": "isExcluded",
          "value": "true"
        }
      }
    ]
  },
  "granularity": {
    "type": "all"
  },
  "dimensions": [
    {
      "type": "LegacyDimensionSpec",
      "dimension": "nativeIdPaths",
      "outputName": "nativeIdPaths",
      "outputType": "STRING"
    },
    {
      "type": "LegacyDimensionSpec",
      "dimension": "pageId",
      "outputName": "pageId",
      "outputType": "STRING"
    }
  ],
  "aggregations": [
    {
      "type": "count",
      "name": "count"
    },
    {
      "type": "thetaSketch",
      "name": "userCount",
      "fieldName": "userId",
      "size": 16384
    }
  ],
  "limitSpec": {
    "type": "default",
    "columns": [
      {
        "dimension": "count",
        "direction": "descending",
        "dimensionOrder": {
          "type": "lexicographic"
        }
      }
    ],
    "limit": 5
  }
}
pageId
and
nativeIdPaths
are multi-value fields, which are sorted using the
SORTED_ARRAY
b
Hi @Viktoryia Shabunia - instead of using
thetaSketch
Can you use a HLL? They will perform better and use much less memory.
Copy code
{
  "type": "HLLSketchBuild",
  "name": "userCount",
  "fieldName": "userId",
  "lgK": 12,
  "tgtHllType": "HLL_4",
  "round": true
}
Also, for dimensionOrder you should probably use:
Copy code
"dimensionOrder": {
          "type": "numeric"
        }
I don't know that it will make a difference, but it can't hurt.
v
Interesting, so the thetaSketch is what causing the large memory footprint? I will talk to our engineers about it. Thank you for the insights
b
ThetaSketches do use a lot of memory. Normally it’s not a problem, but when you’re doing a high cardinality groupBy that effect is magnified.
🙏 1
HLL is more efficient and offers similar accuracy.
v
Is it related to the high cardinality of userId, right and has nothing to do with the multi-value dimensions like nativeIdPaths and pageId, or it's a compound issue
What was not clear to me, is that there was a limit applied, so there should not be a lot of records returned
b
Although there are not a lot returned, it needs to calculate the distinct count for all groups, which is a very heavy query. If you were only grouping by a single userId dimension, you could use a TopN query, which would run faster.
v
Got it, this make sense
Thank you, @Benjamin Hopp
I ran this query 2 times now. One w/o any modification and the context of the query from the logs was as follows: {"query/time":129,"query/bytes":1099,"success":true,"identity":"allowAll"} If I run the query with suggested changes, I see the query/bytes is lower, however the query/time increased. {"query/time":181,"query/bytes":1089,"success":true,"identity":"allowAll"}
I'm still new to druid and trying to understand wether the context is a reliable way to see the improvement
oh, the context probably has nothing to do with the internal merging
so the
query/bytes
is lower not because of HLL
b
Correct. The query/bytes is just the size of the data returned. However, both of those are performing pretty well it seems. You can disable caching to get a better measure of the performance, but there will always be slight variability.