[
https://issues.apache.org/jira/browse/HDDS-16928?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-16928:
------------------------------
Attachment:
MC-1-test-follower-scm-catches-up-after-failed-checkpoint-install.patch
> SCM never catches up after a checkpoint install that fails or is interrupted
> once Ratis has acknowledged it, even after a restart
> ---------------------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-16928
> URL: https://issues.apache.org/jira/browse/HDDS-16928
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Siyao Meng
> Priority: Major
> Attachments:
> MC-1-test-follower-scm-catches-up-after-failed-checkpoint-install.patch,
> TestBugMC1FailedInstallWedgesFollower.java
>
>
> h3. Mechanism
> {{SCMStateMachine.notifyInstallSnapshotFromLeader}} completes its future with
> the checkpoint TermIndex as soon as the leader's checkpoint is downloaded and
> verified. The DB swap is deferred to {{SCMStateMachine.reinitialize}}, which
> Ratis runs later on the {{StateMachineUpdater}} thread. On the next install
> notification Ratis (3.3.1) pauses the state machine and signals the
> {{StateMachineUpdater}} thread to run {{reinitialize}}, but does not wait for
> it: in the same call it purges the follower's Raft log up to the checkpoint
> index and replies SNAPSHOT_INSTALLED, and the leader continues with the
> entries after that index. {{reinitialize}} then calls
> {{SCMHAManagerImpl.installCheckpoint}}.
> If that install fails, every failure path keeps the old DB (failed backup
> move, failed copy with restore, failed reload with rollback), and SCM shuts
> down. The same holds if the process is killed after the acknowledgement and
> before {{HAUtils.replaceDBWithCheckpoint}} moves the old DB aside (argued,
> not run); a kill during the copy leaves the {{dbInconsistentMarker}} file,
> and the SCM then refuses to start. The pending checkpoint was only held in
> memory. After a restart the applied index is the old DB's (for a new SCM, -1)
> while the Raft log starts after the checkpoint index, so
> {{StateMachineUpdater}} never finds the next entry to apply. The leader does
> not send another install notification, because the follower's next index is
> already inside the leader's log.
> h3. Trigger
> # An SCM installs the leader's checkpoint through the Ratis install
> notification. At default settings
> ({{ozone.scm.ha.ratis.log.purge.enabled=false}}) this is in practice an SCM
> that is bootstrapping (new or replaced node); with purge enabled, also a
> follower that fell behind.
> # The leader commits at least one more entry that reaches this SCM before the
> install completes (any SCM write traffic).
> # {{installCheckpoint}} fails with the old DB kept, or the process is killed
> after the acknowledgement and before the old DB is moved aside (a kill during
> the copy leaves the {{dbInconsistentMarker}}, and the SCM then refuses to
> start). Realistic causes are a full disk during the copy of the whole DB, an
> I/O error, or a failure while reloading the SCM services from the new DB. In
> the reproduction the failure is forced with a leftover
> {{dbInconsistentMarker}} file in the DB directory, which makes
> {{HAUtils.replaceDBWithCheckpoint}} fail and restore the old DB. The kill
> case was not run. For a bootstrapping SCM this needs the leader to have added
> it to the Raft group, which happens within moments of the acknowledgement,
> long before a copy of a real DB ends; when the injected immediate failure
> came first, the bootstrap did not complete instead (not followed further).
> # The SCM is restarted.
> h3. Impact
> * The restarted SCM never applies another transaction and never starts its
> datanode server, with no error beyond the periodic "Deferred datanode-server
> start is still waiting for follower catch-up" warning. Nothing recovers it
> automatically.
> * A graceful stop of that SCM never completes ({{StateMachineUpdater}} waits
> to reach the commit index), and its updater thread spins on one core.
> * Its Raft log is complete, so it can become leader. After a leadership
> transfer to it (admin {{transferLeadership}}), it was the Ratis leader and no
> SCM reported itself as a ready leader for the 20 s observed, so the SCM
> service was unavailable. I did not run an election that picks it without the
> transfer.
> * Recovery needs an operator: kill it, remove its SCM DB and Ratis storage,
> and bootstrap it again (argued, not run).
> h3. Reproduction
> PASS on unmodified source, default configuration.
> [^TestBugMC1FailedInstallWedgesFollower.java]
> ({{hadoop-ozone/integration-test}}) starts three SCMs with one inactive,
> places the marker file in the inactive SCM's DB directory, starts it while
> the leader keeps allocating containers, waits until it shuts down after the
> failed install, removes the file and restarts it. Result: SNAPSHOT_INSTALLED
> and the leader moving to the next index logged before the install ran; after
> the restart applied index -1 before and after, log start 90, commit 192
> against leader applied 191, 0 install notifications, datanode server not
> started, 0 of 80 containers, about 9.7 s of updater CPU in 10 s; after a
> leadership transfer to it, it was the Ratis leader and no SCM was a ready
> leader; a graceful stop still running after 20 s. In this JVM the restarted
> SCM gets new datanode and gRPC ports, because the stopped instance keeps them
> bound; a process exit releases them. If the injected failure comes before the
> leader has added the SCM to the Raft group, the test aborts and has to be
> rerun. A passing test means the defect is present.
> h3. Suggested fix
> SCM cannot undo the purge and the acknowledgement from {{reinitialize}}.
> Recommended: install the checkpoint inside the notification future, as
> {{OzoneManagerStateMachine.notifyInstallSnapshotFromLeader}} does, and fail
> the future on any error, so Ratis neither purges nor acknowledges a failed
> install. This reverses the deferral chosen in HDDS-5173 and needs the updater
> to be quiesced during the swap. It should not copy OM's handling of a failed
> install, which completes the future with null (HDDS-11470). As a safety net,
> SCM should check at startup whether its applied index is below the start of
> its Raft log and fail with a clear message; that also catches the same state
> reached through other paths, such as a transaction buffer init failure in
> {{reinitialize}} or a reload failure that rolls back to the old DB.
> Alternatives: change Ratis to purge and reply SNAPSHOT_INSTALLED only after
> {{reinitialize}} has succeeded, or persist the pending checkpoint before
> acknowledging and install it at startup.
> h3. Patch
> [^MC-1-test-follower-scm-catches-up-after-failed-checkpoint-install.patch],
> against b0aa6475b7856d2c7f467dd3db12b9a1dd116f63, test only. It also applies
> to master at 52812559dad.
> It adds {{testSCMCatchesUpAfterFailedCheckpointInstall}} to
> {{TestStorageContainerManagerHA}}. A follower SCM that is a voting member
> falls behind the start of the leader's log (log purge enabled, one snapshot
> requested on the leader), and when it restarts its install fails once in
> {{installCheckpoint}} with the old DB in place (its metadata store, set
> through {{SCMConfigurator.setMetadataStore}}, refuses to stop once). After
> another restart the follower must catch up with the leader. On the current
> code it fails with "Timed out waiting for condition": the follower stays at
> applied index 42 while the leader is at 1475 and the follower's log starts at
> 1261, and the teardown then takes several minutes (about 5) because the
> wedged SCM's stop does not complete. It is meant to land with the fix. A
> member follower is used instead of the bootstrap case of the reproduction
> because an injected failure is immediate, and for a bootstrapping SCM it can
> come before the leader has added the SCM to the Raft group.
> Found by TLA+ model checking and code review of the SCM Ratis snapshot and
> checkpoint install paths under HDDS-15926, on commit
> b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. Checked against HDDS and RATIS
> issues and apache/ozone pull requests for duplicates before filing. The
> attached patch is a test proposal for review. Generated with Specula (Claude
> Opus 5.5).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]