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

HDDS-12483. Quasi Closed Stuck should have 2 replicas of each origin #8014

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

sodonnel
Copy link
Contributor

@sodonnel sodonnel commented Mar 5, 2025

What changes were proposed in this pull request?

After the change to ensure Quasi Closed replicas only move to CLOSED when all 3 origin are present, some new edge cases appeared where some replicas do not get full replication.

After some discussion we decided on the following for Quasi Closed Stuck containers:

  1. If there is only 1 origin available, create 3 copies of it.

  2. If there are 2 or more origins, maintain 2 copies of each origin.

In the worse case, which is:

Origin: 1, bcsid:10, State: Quasi_Closed
Origin: 2, bcsid:10, State: Quasi_Closed
Origin: 3, bcsid:11, State: Unhealthy

This cannot move to closed as the highest BCSID is unhealthy, so 6 replicas will be maintained in the system - 2 from each origin.

This PR solves this issue by introducing a new replication check handler for QC Stuck containers which runs before the existing Ratis Under Replicated Handler.

When under replication is identified a new QuasiClosedStuckUnderReplicationHandler is introduced to process it separately from the existing under replication flow.

Implementing in this way, isolates the special handling into their own code units, and avoids making changing to existing handles which could result in unexpected side effects in complex areas.

Note a followup PR will be required for Over Replication handling.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-12483

How was this patch tested?

New unit and RM scenario tests added / modified.

@sodonnel sodonnel requested a review from siddhantsangwan March 5, 2025 17:47
Comment on lines 49 to 52
if (hasEnoughOriginsWithOpen(containerInfo, replicas)) {
// If we have all origins with open replicas, and not unhealthy then the container should close after the close
// goes through, so this handler should not run.
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

I need some more clarity on this one. Are we waiting for the open replicas to move to quasi_closed first? So there's a mix of open and quasi_closed replicas right now?

hasEnoughOriginsWithOpen also counts quasi_closed replicas, not clear about that as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My intended logic is that if you have 3 origin such that you have:

QC - Origin 1
QC - Origin 2
Open - Origin 3

Then this is not really QC stuck because the open one should go to QC and then you have enough replicas to closed it, as we have all 3 origins.

The mis-matched-replicas-handler will issue the close command, but it also returns false always to let other handler run.

I think then, if we do nothing the normal under replication handling would take care of under replication in this scenario, ie only have 2 replicas.

If the OPEN replica never closes (don't think I have ever seen that occur in practice) I am not sure what we should do!

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, that makes sense. I'll continue reviewing and thinking about this in the context of the whole PR.

Copy link
Contributor

@siddhantsangwan siddhantsangwan left a comment

Choose a reason for hiding this comment

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

Suppose there are two unique origins, and this new logic has made it such that there are two replicas of each origin. So in total there are 4 replicas. Will QuasiClosedStuckReplicationCheck return false in this case, and then the regular replication check handler could end up queuing this container as over replicated?

@sodonnel
Copy link
Contributor Author

Suppose there are two unique origins, and this new logic has made it such that there are two replicas of each origin. So in total there are 4 replicas. Will QuasiClosedStuckReplicationCheck return false in this case, and then the regular replication check handler could end up queuing this container as over replicated?

That might be possible. I probably need to add a clause to the RatisReplicationCheckHandler to not run if shouldHandleAsQCStuck is true. I must not have any scenario tests for that, as if its a problem they should catch it.

@nandakumar131 nandakumar131 self-requested a review March 10, 2025 15:11
@sodonnel
Copy link
Contributor Author

uppose there are two unique origins, and this new logic has made it such that there are two replicas of each origin. So in total there are 4 replicas. Will QuasiClosedStuckReplicationCheck return false in this case, and then the regular replication check handler could end up queuing this container as over replicated?

You were correct - I have added some scenario tests and a fix that avoid this under / over replication loop.

mutablePendingOps.add(ContainerReplicaOp.create(ContainerReplicaOp.PendingOpType.ADD, target, 0));
totalCommandsSent++;
} catch (CommandTargetOverloadedException e) {
LOG.warn("Cannot replicate container {} because target {} is overloaded.", containerInfo, target);
Copy link
Contributor

Choose a reason for hiding this comment

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

It's the sources that are overloaded here, as the push replicate commands are being sent to them. So instead of target we need to log sourceDatanodes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, well spotted. I keep getting source and target confused! I will fix this.

Comment on lines +316 to +317
ContainerID.valueOf(1), QUASI_CLOSED,
Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_SERVICE), Pair.of(origin1, IN_MAINTENANCE),
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this count as over replication? Min healthy for maintenance is one. So for origin1, one in-service replica and one maintenance replica should be sufficient.

Copy link
Contributor

@siddhantsangwan siddhantsangwan left a comment

Choose a reason for hiding this comment

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

@sodonnel Looks good other than the comments I left. We can decide whether we want to handle mis-replication when only one origin is present.

It'd also be good to have some test cases for multiple origins + under replication in TestQuasiClosedStuckReplicationCheck.

@sodonnel
Copy link
Contributor Author

It'd also be good to have some test cases for multiple origins + under replication in TestQuasiClosedStuckReplicationCheck.

I have added only basic tests to the replication check test for the edge cases, then I have tried to cover all scenarios in the scenario based tests. If we do them in both places, then it duplicates the tests, and the scenario ones are a lot more readable I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants