[
https://issues.apache.org/jira/browse/HDDS-16916?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-16916:
------------------------------
Attachment: CR-1-delete-post-rotation-state-off-the-notifying-thread.patch
> New SCM leader blocks its Ratis log applying thread and terminates when the
> root CA post-processing state is stale
> ------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-16916
> URL: https://issues.apache.org/jira/browse/HDDS-16916
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Siyao Meng
> Priority: Major
> Attachments:
> CR-1-delete-post-rotation-state-off-the-notifying-thread.patch,
> TestBugCR1LeaderReadyBlockingWrite.java
>
>
> h3. Mechanism
> {{SCMStateMachine.notifyLeaderReady}} runs on the Ratis
> {{StateMachineUpdater}} thread and notifies the SCM services inline.
> {{RootCARotationManager.notifyStatusChanged}} then calls
> {{checkAndHandlePostProcessing}} on that thread. After a root CA rotation the
> leader saves the new root certificate as the stateful configuration of
> {{RootCARotationManager}} and schedules its deletion one
> {{hdds.x509.rootca.certificate.polling.interval}} (default 2h) later. If a
> new leader still finds the entry after that window, which it measures from
> the {{notBefore}} of the root certificate, {{checkAndHandlePostProcessing}}
> calls {{deleteConfiguration}}. That is a replicated call which waits until
> its log entry is applied, and the only thread that can apply it is the one
> waiting. After {{ozone.scm.ha.ratis.request.timeout}} (default 30s) the call
> fails, {{notifyStatusChanged}} rethrows the failure as a
> {{RuntimeException}}, Ratis closes the server because the
> {{StateMachineUpdater}} caught a {{Throwable}}, and {{SCMStateMachine.close}}
> terminates the SCM.
> The same inline delete exists in the branch for an entry whose root
> certificate is older than the local one (code reading, exercised at unit
> level by the test in the patch).
> The same inline call is in the release tags ozone-1.4.0, 1.4.1, 2.0.0, 2.1.0,
> 2.1.1, 2.1.2, 2.2.0 and 2.2.1 (read, not run). In 1.4.0 and 1.4.1 the
> services are notified from {{SCMStateMachine.notifyTermIndexUpdated}}, which
> the stack trace in HDDS-11750 shows on the same thread.
> h3. Trigger
> # Secure SCM HA with {{hdds.x509.ca.rotation.enabled=true}} (default false).
> # A root CA rotation completes.
> # The leader that ran the rotation loses leadership before its scheduled
> deletion runs, which is one polling interval after the rotation finished.
> Run: the leader stops one second before the end of the window. By code
> reading a step down has the same effect, because it cancels the deletion task.
> # The next SCM becomes leader ready, out of safe mode, later than one polling
> interval after the {{notBefore}} of the new root certificate. A leader change
> that is complete before that point is harmless, because the new leader then
> only schedules the deletion for the rest of the window.
> The points in time of steps 3 and 4 differ. The new root certificate is
> created when the rotation starts and the leader schedules the deletion when
> the rotation finishes, so the point of step 4 comes first by the time the
> rotation took. That was about 1.3s in the run. By code reading it is limited
> by the wait for the sub CA acknowledgements,
> {{hdds.x509.ca.rotation.ack.timeout}} (default 15 minutes), plus the
> replicated calls of the rotation, and a leader election between the two
> points is enough, with no time without a leader. An admin leadership transfer
> does not get there, because the leader refuses it while its deletion is
> pending (run inside the window).
> If the scheduled deletion itself fails, the failure is only logged and not
> retried (code reading). The entry then stays, and the next SCM that becomes
> leader ready out of safe mode is affected whenever that happens.
> By code reading, an SCM that becomes leader while still in safe mode is not
> affected, because the check then runs later on the thread that leaves safe
> mode.
> h3. Impact
> * The new leader applies no log entry for 30s and then stops. In the run the
> SCM was stopped from its {{StateMachineUpdater}} thread and reached
> {{ExitUtils.terminate}} with status 0 ("scm statemachine is closed by ratis,
> terminate SCM"). The run used the mini cluster, where the JVM exit is
> disabled. A separate SCM process was not run.
> * Nothing brings the SCM back, it stays down until it is restarted.
> * In the run the previous leader was down as well, so the three SCM ring was
> left with one SCM and no quorum. If the previous leader is still up, two SCMs
> remain and can elect a leader (argued, not run).
> * No replicated state is damaged. The delete entry stays in the Ratis log, so
> it should be applied under the next leader and the failure should not repeat
> (argued, not run).
> * Rotation happens about once per root certificate lifetime
> ({{hdds.x509.max.duration}}, default P1865D). The leader change has to
> straddle the end of the window after it (the old leader loses leadership
> before its deletion runs, the next leader becomes ready after the window), or
> come at any later time if the scheduled deletion failed.
> h3. Reproduction
> PASS, unmodified source, nothing injected.
> [^TestBugCR1LeaderReadyBlockingWrite.java]
> ({{hadoop-ozone/integration-test}}) starts a secure mini cluster with three
> SCMs. Certificate lifetimes are shortened so that the leader rotates the root
> CA two minutes after SCM init, and the polling interval is 20s instead of 2h.
> The test stops the leader one second before the window ends and then finds
> the {{StateMachineUpdater}} thread of the new leader inside
> {{deleteConfiguration}}, called from {{SCMStateMachine.notifyLeaderReady}}.
> 30s later the Ratis division of the new leader is closing and the SCM stops.
> The test takes about three minutes. A passing test means the defect is
> present.
> h3. Patch
> [^CR-1-delete-post-rotation-state-off-the-notifying-thread.patch], against
> b9b33851b20fa11baf4b07982de9afb8ea44f85a. It also applies to master at
> 5108acff480. The patch is written against that commit alone, so other fixes
> proposed for {{RootCARotationManager}} and its unit test will need a manual
> merge with it.
> {{checkAndHandlePostProcessing}} hands its two replicated deletes (the entry
> past its window and the entry older than the local root certificate) to the
> executor of the manager, which already runs the scheduled deletion. A failed
> delete is logged like a failed scheduled deletion, and the entry is checked
> again after the next leader change. Everything else stays on the notifying
> thread and is unchanged: reading the entry, setting the flag that blocks
> certificate signing inside the window, and any failure of the read or of the
> comparison, for example an entry naming a newer root certificate than the
> local one, which ends the SCM as before.
> {{SecretKeyManagerService.notifyStatusChanged}} in the same package also runs
> its replicated call on its own executor.
> Covered in the existing {{TestRootCARotationManager}} by
> {{testStalePostProcessingStateIsDeletedOffNotifyingThread}}, which fails for
> both deletes without the change because the delete runs on the notifying
> thread and its failure is thrown to the caller, and by
> {{testFailedPostProcessingCheckIsThrownToNotifier}}, which holds the
> unchanged failure of the check in place and passes with and without the
> change. With the change the SCM HA and root CA rotation unit suites of
> {{hadoop-hdds/server-scm}} pass (115 tests) and checkstyle is clean. In the
> reproduction the new leader is then ready 5.6s after the old leader stopped,
> deletes the entry from the executor thread 6ms after the check and keeps
> running, so the reproduction fails at its first assertion.
> Related issues, none of which covers this call. HDDS-11750 reported the same
> self wait for {{LegacyReplicationManager.notifyStatusChanged}} and was
> resolved as Won't Fix without a code change, and that class has since been
> removed. HDDS-16029 (open) is a different blocking call,
> {{ContainerBalancer}} joining its thread when the SCM loses leadership.
> HDDS-16222 (open) proposes a static check that {{notifyStatusChanged}} cannot
> block and names those two issues, not this call.
> Found by code review of the SCM root CA rotation paths, as part of the TLA+
> verification effort under HDDS-15926, on commit
> b9b33851b20fa11baf4b07982de9afb8ea44f85a. Checked against HDDS issues and
> apache/ozone pull requests for duplicates before filing. The attached patch
> is a 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]