Skip to content

Health API - Monitoring local disk health#88390

Merged
elasticsearchmachine merged 28 commits intoelastic:mainfrom
gmarouli:health-disk-monitor-health
Aug 3, 2022
Merged

Health API - Monitoring local disk health#88390
elasticsearchmachine merged 28 commits intoelastic:mainfrom
gmarouli:health-disk-monitor-health

Conversation

@gmarouli
Copy link
Copy Markdown
Contributor

@gmarouli gmarouli commented Jul 8, 2022

This PR introduces the local health monitoring functionality needed for #84811 . The monitor uses the NodeService to get the disk usage stats and determines the node's disk health.

When a change in the disk's is detected or when the health node changes, this class would be responsible to send the node's health to the health node. Currently this is simulated with a method that just logs the current health.

The monitor keeps the last reported health, this way, if something fails on the next check it will try to resend the new health state.

@gmarouli gmarouli mentioned this pull request Jul 8, 2022
9 tasks
@gmarouli gmarouli changed the title Health disk monitor health Health API - Monitoring local disk health Jul 8, 2022
@gmarouli gmarouli force-pushed the health-disk-monitor-health branch from 5013389 to d636893 Compare July 21, 2022 08:56
@elasticsearchmachine elasticsearchmachine changed the base branch from master to main July 22, 2022 23:05
@gmarouli
Copy link
Copy Markdown
Contributor Author

@elasticmachine update branch

@mark-vieira mark-vieira added v8.5.0 and removed v8.4.0 labels Jul 27, 2022
@gmarouli
Copy link
Copy Markdown
Contributor Author

@elasticmachine update branch

@gmarouli gmarouli requested a review from andreidan July 28, 2022 12:56
@gmarouli gmarouli added >non-issue :Distributed/Health Issues for the health report API labels Jul 28, 2022
@gmarouli gmarouli marked this pull request as ready for review July 28, 2022 14:27
@elasticsearchmachine elasticsearchmachine added the Team:Data Management (obsolete) DO NOT USE. This team no longer exists. label Jul 28, 2022
@elasticsearchmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-data-management (Team:Data Management)

Copy link
Copy Markdown
Contributor

@andreidan andreidan 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 working on this Mary

I left a first set of comments (and a suggestion to break this PR up)

if (healthMetadataInitialized == false) {
healthMetadataInitialized = HealthMetadata.getFromClusterState(event.state()) != null;
if (healthMetadataInitialized) {
scheduleNextRunIfEnabled(TimeValue.timeValueMillis(1));
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.

I think this should schedule based the monitoring based on the normal interval

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.

hm, you mean that if it gets rescheduled it should have the initial delay?

I have to admit that when I see something executed at an interval I do not expect to have an initial delay. I expect that it's going to be executed asap and then wait for the interval before the next execution. For example let's say that the interval is 10 minutes. I would think it's wrong to wait for 10 minutes before running it for the first time.

What do you think?

@gmarouli
Copy link
Copy Markdown
Contributor Author

Update:

  • The sending is removed and left for the next PR.
  • We use scheduleUnlessShuttingDown and used an AtomicBoolean to ensure the single execution of the monitoring. I like this approach more. I think this reads better and it doesn't do extra cancelling and scheduling. If there are multiple runs scheduled at the same time only one will run, the other ones will just do nothing. What do you think?

@gmarouli gmarouli requested a review from andreidan July 29, 2022 12:46
@gmarouli
Copy link
Copy Markdown
Contributor Author

gmarouli commented Jul 29, 2022

Investigating the test failure. I can reproduce the failure locally too with this seed:

./gradlew ':server:test' --tests "org.elasticsearch.health.node.LocalHealthMonitorTests.testEnablingAndDisabling" -Dtests.seed=C307AA9DA1F7BA82 -Dtests.locale=es-CO -Dtests.timezone=Etc/Greenwich -Druntime.java=17

@gmarouli
Copy link
Copy Markdown
Contributor Author

Test fixed. The issue was that we removed the scheduled field that was used both to cancel a run but also to signal not allow setting changes to schedule runs. Fixed by using healthMetadataInitialized for the same purpose.

@gmarouli
Copy link
Copy Markdown
Contributor Author

@elasticmachine update branch

@gmarouli
Copy link
Copy Markdown
Contributor Author

@elasticmachine run elasticsearch-ci/packaging-tests-unix-sample

Copy link
Copy Markdown
Contributor

@andreidan andreidan 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 iterating on this Mary

Left a few more suggestions

if (inProgress.compareAndSet(false, true)) {
ClusterState clusterState = clusterService.state();
HealthMetadata healthMetadata = HealthMetadata.getFromClusterState(clusterState);
assert healthMetadata != null : "health metadata should have been initialized.";
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.

is this assertion fair?

The master node might've not initialised the health metadata but the monitor might be running because the service is enabled ?

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.

Before we schedule any monitoring task we check the flag healthMetadataInitialized so theoretically this should hold true. The only case I can think of, is if someone removes the health metadata. But I think we do not give that option programmatically. Would you prefer to have an if here?

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.

Ah, right. The HealthMetadataService is controlled by a different setting - enabled/disabled via health.node.enabled so that made me think things can diverge.
I prefer the explicit checks, but it's a personal preference so feel free to ignore

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.

They are all controlled by the same flag health.node.enabled. The reason I have done this, is that if the health node is disabled, there is no point to monitor the disk health locally, or to publish health metadata right?

On a second thought, depending on the use case @jbaiera is working on we might want to decouple this and have the health metadata always be published. They might be useful for the coordinator node too.

// Wait until every node in the cluster is upgraded to 8.4.0 or later
if (event.state().nodesIfRecovered().getMinNodeVersion().onOrAfter(Version.V_8_4_0)) {
// Wait until the health metadata is available in the cluster state
if (healthMetadataInitialized == false) {
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.

This flag is a little misleading as it waits for a bit more than just the metadata to be initialised (ie. nodes versions). Could we rename it to reflect that?

Also, if the service is enabled,disabled, and enabled again we might end up with 2 scheduled monitoring tracks? (since setEnabled doesn't check if we're already running?)

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.

About the scheduling two monitoring tasks. That's true, but then one will see that the inProgress flag is not false and it will just exit without doing anything or scheduling anything. I thought it was good trade-off compared to locking. What do you think?

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.

Yes ! That's a good trade-off 🚀 Can you please document it?

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.

Ah yes! Good point.

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.

Done, let me know if it's clear.

Copy link
Copy Markdown
Contributor Author

@gmarouli gmarouli Aug 1, 2022

Choose a reason for hiding this comment

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

Also renamed healthMetadataInitialized to something more inclusive.

@gmarouli gmarouli requested a review from andreidan August 1, 2022 19:42
Copy link
Copy Markdown
Contributor

@andreidan andreidan 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 iterating on this.

Left a could more comments

// monitoring tasks scheduled, one of them will be no-op.
private final AtomicBoolean inProgress = new AtomicBoolean();
// Keeps the latest health state that was successfully reported.
private DiskHealthInfo lastReportedDiskHealthInfo = null;
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.

should this be volatile to ensure it's written to main memory? (being written from another thread, without volatile it might not be immediately visible as it'll not be flushed to main memory ie. getLastReportedDiskHealthInfo might not see the "last reported" info)

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.

Yeap, I probably removed it accidentally at some point.

Comment on lines +103 to +107
if (prerequisitesFulfilled == false) {
prerequisitesFulfilled = event.state().nodesIfRecovered().getMinNodeVersion().onOrAfter(Version.V_8_5_0)
&& HealthMetadata.getFromClusterState(event.state()) != null;
scheduleNowIfEnabled();
}
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.

this seems to schedule the polling even if the prerequisites were not fulfilled?

could the version check be still 8_4_0 as we have the metadata already? or is there a reason we should wait for 8.5?

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.

Hm, I think I need to rename this method. We check the prerequisites in the method scheduleNowIfEnabled. This was a choice I made to ensure the prerequisites are always checked before any scheduling. For this reason it felt redundant to check it again here. What do you think about renaming to maybeScheduleNow() indicating that it is not a given that it will schedule it?

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.

About 8.5.0 you are right the healthMetadata do exists in 8.4.0 but this local monitor will be pushing changes to the HealthNode and that endpoint is not implemented in 8.4.0. That's why I thought that the minimum required version should be 8.5.0. Does this make sense?

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.

Ah ++ fair enough

Copy link
Copy Markdown
Contributor

@andreidan andreidan left a comment

Choose a reason for hiding this comment

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

LGTM thanks for iterating on this Mary 🚀

@gmarouli
Copy link
Copy Markdown
Contributor Author

gmarouli commented Aug 3, 2022

@elasticmachine update branch

@gmarouli
Copy link
Copy Markdown
Contributor Author

gmarouli commented Aug 3, 2022

@elasticmachine run elasticsearch-ci/part-1

@gmarouli
Copy link
Copy Markdown
Contributor Author

gmarouli commented Aug 3, 2022

@andreidan thanks for the feedback!

@gmarouli gmarouli added the auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) label Aug 3, 2022
@elasticsearchmachine elasticsearchmachine merged commit d828c2a into elastic:main Aug 3, 2022
@gmarouli gmarouli deleted the health-disk-monitor-health branch August 3, 2022 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) :Distributed/Health Issues for the health report API >non-issue Team:Data Management (obsolete) DO NOT USE. This team no longer exists. v8.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants