Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add worker status and duration metrics in live and task reports #15180

Merged

Conversation

gargvishesh
Copy link
Contributor

@gargvishesh gargvishesh commented Oct 17, 2023

Description

Add worker status and duration metrics in live and task reports for tracking. Format:

  "workers": {
    "0": [
      {
        "workerId": "query-df8d9f94-58ba-4d99-8d01-7eb42d547a7e-worker0_0",
        "state": "SUCCESS",
        "durationMs": 2561
      }
    ],
    "1": [
      {
        "workerId": "query-df8d9f94-58ba-4d99-8d01-7eb42d547a7e-worker1_0",
        "state": "FAILED",
        "durationMs": 500
      },
      {
        "workerId": "query-df8d9f94-58ba-4d99-8d01-7eb42d547a7e-worker1_1",
        "state": "RUNNING",
        "durationMs": -1
      }
    ]
  }
  • 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.

@github-actions github-actions bot added Area - Batch Ingestion Area - MSQ For multi stage queries - https://github.com/apache/druid/issues/12262 labels Oct 17, 2023
@gargvishesh gargvishesh changed the title Add worker status and duration metrics in task report Add worker status and duration metrics in live and task reports Oct 17, 2023
@gargvishesh gargvishesh marked this pull request as ready for review October 18, 2023 08:33
Copy link
Contributor

@cryptoe cryptoe left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @gargvishesh. Left an initial review.
Should be good to go once the comments are addressed.

{
final Map<Integer, List<WorkerStats>> workerStats = new TreeMap<>();

for (Map.Entry<String, TaskTracker> taskEntry : taskTrackers.entrySet()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

private final Map<String, TaskTracker> taskTrackers = new LinkedHashMap<>();
was only called from the main worker loop until now.
WIth this change, the taskTrackers can be called from the jetty thread or the main controller impl thread.

So we should either make TaskTracker thread safe

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Now wrapped in Collections.synchronizedMap(). Believe this won't have any significant impact on performance.

Copy link
Contributor

Choose a reason for hiding this comment

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

Lets use a concurrentHashMap ?

Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee serial access, it is critical that all access to the backing map is accomplished through the returned map.
It is imperative that the user manually synchronize on the returned map when traversing any of its collection views via Iterator, Spliterator or Stream:
   Map m = Collections.synchronizedMap(new HashMap());
       ...
   Set s = m.keySet();  // Needn't be in synchronized block
       ...
   synchronized (m) {  // Synchronizing on m, not s!
       Iterator i = s.iterator(); // Must be in synchronized block
       while (i.hasNext())
           foo(i.next());
   }
  

Since its every easy to use s.iteratator() no ?

@@ -348,6 +351,68 @@ public boolean isTaskLatest(String taskId)
}
}

public static class WorkerStats
{
String workerId;
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets mark these field final ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can't - because of the default constructor.

/**
* For JSON deserialization only
*/
public WorkerStats()
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually want serialization only rite ? so this method can go no ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Many tests in SQLMSQStatementResourceTypeTest fail as they require deserialization -- such as testReplaceAll, testWithDurableStorage, and testResultFormatWithParamInSelect

this.duration = duration;
}

@JsonProperty()
Copy link
Contributor

Choose a reason for hiding this comment

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

nit is the () required ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed. Thanks!


TaskTracker taskTracker = taskEntry.getValue();

long duration = (taskTracker.status.getDuration() == -1
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it should be okay to remove the -1 duration check and always report taskTracker.status.getDuration().
We always rely on the overlord system to gives us the task duration without changing anything.
wdyt ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason was that duration is always -1 for RUNNING workers (since it gets updated only upon completion), so publishing their duration wouldn't ever be useful.

Copy link
Contributor

Choose a reason for hiding this comment

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

MSQ tracks the start time as the time it requested to launch the job. I currently do not know if duration counter in the overlord is started as soon as the overlord gets the request or when ever that task goes into running state.

To test it what you could do is

  1. Make changes to the MSQWorkerTaskLauncher to log the report every time liveReports is called.
  2. Start a cluster with lets say 4 task slots.
  3. Use 2 slots for other ingestions.
  4. Schedule an MSQ job with 4 slots. (The MSQ job will wait and the worker task launcher will set the start time for each task ).
  5. Kill the job running on the other 2 slots.

Check if the taskDuration in the report is going backward.

Copy link
Contributor Author

@gargvishesh gargvishesh Oct 20, 2023

Choose a reason for hiding this comment

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

Did the check both from a run and in code and found it to be correct: the start time in MSQ is recorded when the task is submitted whereas in overlord is upon start of the run.

Currently TaskStatus doesn't have any field to record a startTime, so for MSQ to get a worker's startTime from the Overlord, this field needs to be added and persisted in the database upon the worker task's start.

There is no such issue with reporting of query's duration periodically in live reports since it's a single hop from (from overlord to indexer) and the query's start time is maintained inside the controller -- so the duration can be calculated on-the-fly.

Since we are more interested in timings of finished workers, I think for now it is fine to just report the duration as -1 for worker tasks instead of adding a new field in TaskStatus which is used at multiple places. But do let me know if you think we should take the route of adding a new field.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for digging in. Reporting -1 for running tasks SGTM.

}

@JsonProperty()
public TaskState getState()
Copy link
Contributor

Choose a reason for hiding this comment

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

We should also document these properties in docs/api-reference/sql-ingestion-api.md

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added these properties.

Copy link
Contributor

@cryptoe cryptoe left a comment

Choose a reason for hiding this comment

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

PR is almost there.

{
final Map<Integer, List<WorkerStats>> workerStats = new TreeMap<>();

for (Map.Entry<String, TaskTracker> taskEntry : taskTrackers.entrySet()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets use a concurrentHashMap ?

Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee serial access, it is critical that all access to the backing map is accomplished through the returned map.
It is imperative that the user manually synchronize on the returned map when traversing any of its collection views via Iterator, Spliterator or Stream:
   Map m = Collections.synchronizedMap(new HashMap());
       ...
   Set s = m.keySet();  // Needn't be in synchronized block
       ...
   synchronized (m) {  // Synchronizing on m, not s!
       Iterator i = s.iterator(); // Must be in synchronized block
       while (i.hasNext())
           foo(i.next());
   }
  

Since its every easy to use s.iteratator() no ?

@@ -111,7 +115,7 @@ private enum State
// Mutable state accessible only to the main loop. LinkedHashMap since order of key set matters. Tasks are added
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets update the comments as well.

Copy link
Contributor

@cryptoe cryptoe left a comment

Choose a reason for hiding this comment

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

Changes LGTM.
Thanks @gargvishesh .

@cryptoe cryptoe merged commit 039b055 into apache:master Oct 30, 2023
82 checks passed
CaseyPan pushed a commit to CaseyPan/druid that referenced this pull request Nov 17, 2023
…he#15180)

Add worker status and duration metrics in live and task reports for tracking.
@LakshSingla LakshSingla added this to the 29.0.0 milestone Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area - Batch Ingestion Area - Documentation Area - MSQ For multi stage queries - https://github.com/apache/druid/issues/12262
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants