Skip to content

Use separate executor to handle task updates in TaskQueue - #14533

Merged
kfaraz merged 6 commits into
apache:masterfrom
kfaraz:task_callback_exec
Jul 7, 2023
Merged

kfaraz merged 6 commits into
apache:masterfrom
kfaraz:task_callback_exec

Conversation

@kfaraz

@kfaraz kfaraz commented Jul 6, 2023 •

Copy link
Copy Markdown
Contributor

Description

TaskQueue.notifyStatus is often a heavy call as it performs the following operations:

  • Update task status in metadata DB
  • Update task locks in metadata DB
  • Request (synchronously) the task runner to shutdown the completed task
  • Clean up in-memory data structures

This method can often be slow and can cause worker sync / task runners to slow down.

Changes

  • Run task completion callbacks in a separate executor to handle task completion updates
  • Add config to handle the number of threads of the new callback executor
  • Add metrics to monitor number of processed and queued items
  • Use CoordinatorRunStats to collect and report metrics. This class has been used as is for now but will later be renamed and repurposed across all Druid services.
  • Add TaskCountStatsProvider.getStats() which deprecates the other getXXXTaskCount methods.
  • There are still other paths that can invoke notifyStatus, but those need not be moved to the new executor as they are synchronous on purpose.

Release note

  • Add new config druid.indexer.queue.taskCompleteHandlerNumThreads which controls the number of threads used by the Overlord TaskQueue to handle task completion updates received from the workers.
  • Add new metrics task/status/queue/count, task/status/updated/count

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

}
}

public CoordinatorRunStats getQueueStats()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. These are not coordinator run stats.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have added a comment in the description of this PR about repurposing the CoordinatorRunStats to be generic DruidStats but that will be tackled in a separate PR.

This class is a nice encapsulation to collect and report stats across multiple dimensions and is thread-safe too.

Comment on lines +786 to +787
// The onSuccess and onFailure should be lightweight enough
// so that the executor giving the statusFuture is not blocked

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The onSuccess and onFailure should be lightweight enough
// so that the executor giving the statusFuture is not blocked
// The onSuccess and onFailure should be lightweight enough
// so that the executor giving the statusFuture is not blocked
// We use the direct executor here so we can track in-flight status updates.
// so the metrics for in-flight status gets updated immediately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified this comment, added the rest of the info in the javadoc of this method as it seemed like a better place for detailed richer content.

@kfaraz
kfaraz merged commit 40d0dc9 into apache:master Jul 7, 2023
@kfaraz

kfaraz commented Jul 7, 2023

Copy link
Copy Markdown
Contributor Author

Thanks for the review, @abhishekagarwal87 !

@kfaraz
kfaraz deleted the task_callback_exec branch July 7, 2023 15:13
@vtlim

vtlim commented Jul 14, 2023

Copy link
Copy Markdown
Member

@kfaraz In the release notes, should task/status/handled/count really be task/status/updated/count? From

public static final CoordinatorStat STATUS_UPDATES_IN_QUEUE
= CoordinatorStat.toDebugAndEmit("queuedStatusUpdates", "task/status/queue/count");
public static final CoordinatorStat HANDLED_STATUS_UPDATES
= CoordinatorStat.toDebugAndEmit("handledStatusUpdates", "task/status/updated/count");

@kfaraz

kfaraz commented Jul 14, 2023

Copy link
Copy Markdown
Contributor Author

Yes, @vtlim , thanks for catching this!

@abhishekagarwal87 abhishekagarwal87 added this to the 27.0 milestone Jul 19, 2023
sergioferragut pushed a commit to sergioferragut/druid that referenced this pull request Jul 21, 2023
Description:
`TaskQueue.notifyStatus` is often a heavy call as it performs the following operations:
- Update task status in metadata DB
- Update task locks in metadata DB
- Request (synchronously) the task runner to shutdown the completed task
- Clean up in-memory data structures

This method can often be slow and can cause worker sync / task runners to slow down.

Main changes:
- Run task completion callbacks in a separate executor to handle task completion updates
- Add new config `druid.indexer.queue.taskCompleteHandlerNumThreads`
- Add metrics to monitor number of processed and queued items
- There are still other paths that can invoke `notifyStatus`, but those need not be moved to
the new executor as they are synchronous on purpose.

Other changes:
- Add new metrics `task/status/queue/count`, `task/status/handled/count`
- Add `TaskCountStatsProvider.getStats()` which deprecates the other `getXXXTaskCount` methods.
- Use `CoordinatorRunStats` to collect and report metrics. This class has been used as is
for now but will later be renamed and repurposed to use across all Druid services.
@acherla

acherla commented Aug 9, 2023 •

Copy link
Copy Markdown

@kfaraz I am wondering if we can instead default this to a percentage of CPU cores on the machine type instead of defaulting it to a value of 5 if the value is not present for taskCompleteHandlerNumThreads? Maybe max 30% of available Runtime.getRuntime().availableProcessors() or 5? This would reduce the amount of configuration a user would have to do on initial setup and id consider this feature a pretty big component for the stability of the overlord when a large number of task statuses are updated.

this.taskCompleteHandlerNumThreads = Configs.valueOrDefault(taskCompleteHandlerNumThreads, 5);

@maytasm

maytasm commented May 26, 2025

Copy link
Copy Markdown
Contributor

@kfaraz Any reason these metrics and config property are not in the docs? I don't think this is internal config and can see users setting these if they are high number of indexing tasks

@kfaraz

kfaraz commented May 26, 2025

Copy link
Copy Markdown
Contributor Author

@maytasm , these were originally meant to be an experimental config and metrics. So we didn't document them originally.

Have you encountered cases where the default value of 5 was inadequate?
What value did you end up choosing in that case?

I have personally never had to reconfigure this value or needed to look at the these metrics for any real debugging.
But since they are there, we might as well document them. I can create a PR for that.

I can also implement the suggestion in this comment #14533 (comment) to reduce the config required.

Let me know what you think.

@maytasm

maytasm commented May 26, 2025 •

Copy link
Copy Markdown
Contributor

@kfaraz Our cluster has about 2500 kafka indexing tasks and 3000 compaction related indexing tasks running. When many tasks roll over at the same time, we saw some issues with the overlord not processing the task updates fast enough. We had instances where it was so slow that we exceeded the completionTimeout on the kafka indexing tasks, causing them to fail. Before trying out this change, we manage it by configuring the stopTaskCount on each supervisor and using taskDuration that are prime numbers (to minimize tasks rolling at the same time). The default value of 5 was inadequate for us. We set the config to be 1/3 of the number of CPU we have (which is about 30) and life has been great. task/status/queue/count has been stable and low (no spikes), we haven't had issue with completionTimeout, and didn't need to tune stopTaskCount+taskDuration.

@kfaraz

kfaraz commented May 27, 2025

Copy link
Copy Markdown
Contributor Author

Sounds good, thanks for the details, @maytasm ! I will create a PR to update the docs.

riovic918data added a commit to riovic918data/druid that referenced this pull request Jun 12, 2026
Description:
`TaskQueue.notifyStatus` is often a heavy call as it performs the following operations:
- Update task status in metadata DB
- Update task locks in metadata DB
- Request (synchronously) the task runner to shutdown the completed task
- Clean up in-memory data structures

This method can often be slow and can cause worker sync / task runners to slow down.

Main changes:
- Run task completion callbacks in a separate executor to handle task completion updates
- Add new config `druid.indexer.queue.taskCompleteHandlerNumThreads`
- Add metrics to monitor number of processed and queued items
- There are still other paths that can invoke `notifyStatus`, but those need not be moved to
the new executor as they are synchronous on purpose.

Other changes:
- Add new metrics `task/status/queue/count`, `task/status/handled/count`
- Add `TaskCountStatsProvider.getStats()` which deprecates the other `getXXXTaskCount` methods.
- Use `CoordinatorRunStats` to collect and report metrics. This class has been used as is
for now but will later be renamed and repurposed to use across all Druid services.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants