Siyao Meng created HDDS-16903:
---------------------------------
Summary: HealthyPipelineSafeModeRule counts DORMANT and CLOSED
pipelines, so SCM can leave safe mode with no healthy OPEN RATIS/THREE pipeline
Key: HDDS-16903
URL: https://issues.apache.org/jira/browse/HDDS-16903
Project: Apache Ozone
Issue Type: Bug
Reporter: Siyao Meng
Attachments:
MC-4-count-only-open-pipelines-in-healthy-pipeline-rule.patch,
TestBugMC4NonOpenPipelineCountsAsHealthy.java
h3. Mechanism
While SCM is in safe mode, {{PipelineReportHandler.processPipelineReport}}
fires {{OPEN_PIPELINE}} for every reported pipeline that is healthy (all
members reported, leader known), whatever its state in SCM.
{{HealthyPipelineSafeModeRule.process}}, the only subscriber, checks the
replication config, whether the pipeline was already counted, the member count
and the member health, but not the state. A DORMANT or CLOSED RATIS/THREE
pipeline whose datanodes still host the Ratis group is therefore counted,
although the threshold in {{initializeRule}} is computed from OPEN pipelines
only. The count never goes down, and once every rule has passed SCM does not
return to safe mode.
The other checks in the same area count OPEN pipelines only:
{{OneReplicaPipelineSafeModeRule.process}} checks {{isOpen()}}, and so does the
report free path {{validateHealthyPipelineSafeModeRuleUsingPipelineManager}}
(HDDS-13590). HDDS-4399 ("Safe mode rule for pipelines should only consider
open pipelines") moved the {{fireEvent}} out of the ALLOCATED branch so that
pipelines reloaded as OPEN are counted, and the state check was lost with that
move.
h3. Trigger
Datanodes keep a pipeline's Ratis group, and keep reporting it, until SCM sends
a close command. For a pipeline that was deactivated, or closed by a pipeline
action, an admin close or {{StaleNodeHandler}}, SCM sends it only when the
pipeline scrubber deletes the CLOSED pipeline, and the scrubber runs only
outside safe mode. Two ways to get there:
* DORMANT: an admin runs {{ozone admin pipeline deactivate}}. Only the SCM
state changes, and the state is persisted, so the pipeline counts at every
later SCM restart for as long as its datanodes are up.
* CLOSED: during safe mode a member asks SCM to close the pipeline (pipeline
action, for example after a Ratis failure), an admin runs {{ozone admin
pipeline close}}, or a member goes stale for a while (for example a long GC
pause) and {{StaleNodeHandler}} closes its pipelines before it recovers. The
members keep reporting the pipeline for the rest of safe mode. A pipeline
closed shortly before an SCM restart is loaded as CLOSED and behaves the same
(argued, not run).
SCM leaves safe mode on such a pipeline once the other rules pass, for example
after a restart where an OPEN pipeline has only one live member: that one
member satisfies {{OneReplicaPipelineSafeModeRule}}, but the pipeline cannot
become healthy.
h3. Impact
SCM leaves safe mode although no OPEN RATIS/THREE pipeline is healthy. That is
the situation this rule exists to prevent (HDDS-1178). Block allocation is then
allowed, and new RATIS/THREE writes can only proceed once a new pipeline is
created and opened. Where the datanodes have room for a new pipeline, this
mostly makes the exit earlier. Where they have none (for example, the slots are
held by the DORMANT pipeline), writes keep failing until an operator acts
(argued from the code, not run). No data is lost, and the container rules still
gate the exit. The state check is missing since 1.1.0 (HDDS-4399).
h3. Reproduction
[^TestBugMC4NonOpenPipelineCountsAsHealthy.java] ({{hadoop-hdds/server-scm}})
uses the real {{PipelineManagerImpl}}, {{PipelineReportHandler}},
{{PipelineActionHandler}} and {{SCMSafeModeManager}} with all its rules, driven
only by datanode registration, pipeline report and pipeline action events.
Pipeline P1 is OPEN with one live member. Pipeline P2 is on three other live
datanodes and is deactivated before the start (first test), or closed by a
member's close action during safe mode (second test). Before P2's members
report it, only {{HealthyPipelineSafeModeRule}} is unmet. After their reports,
SCM leaves safe mode with P1 as the only OPEN RATIS/THREE pipeline and P1 not
healthy. Both tests pass on unmodified source, which means the defect is
present. With the patch, both fail because SCM stays in safe mode. The
reproduction does not model datanodes opening pipelines that the background
pipeline creator allocates.
h3. Patch
[^MC-4-count-only-open-pipelines-in-healthy-pipeline-rule.patch], against
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at
a5aeb764d80.
{{HealthyPipelineSafeModeRule.process}} reads the pipeline's current state from
{{PipelineManager}} and skips it unless it is OPEN, as
{{OneReplicaPipelineSafeModeRule}} does. The check is in the rule rather than
in {{PipelineReportHandler}} for two reasons. The {{Pipeline}} object the
handler fires is the copy it read before calling {{openPipeline}}, so it still
says ALLOCATED for a pipeline that the same report has just opened. And the
event is processed asynchronously. {{PipelineReportHandler}} is unchanged.
One behaviour change: if the only fully reported RATIS/THREE pipelines are
DORMANT or CLOSED and no OPEN one can become healthy, SCM now stays in safe
mode until one does or an operator runs {{ozone admin safemode exit}}, instead
of leaving it without a writable pipeline. With the default
{{hdds.scm.safemode.pipeline.creation=true}} a CLOSED pipeline only delays the
exit while three healthy datanodes remain: CLOSED pipelines do not count
against the datanode pipeline limit, so the background creator builds a new
one. The case that changes is DORMANT pipelines taking every free pipeline
slot, for example an admin who deactivates all pipelines and then restarts SCM.
SCM then stays in safe mode, so {{ReplicationManager}} does not run either,
until the admin activates a pipeline or runs {{ozone admin safemode exit}}.
Covered by {{testPipelineNotOpenIsIgnored}} in the existing
{{TestHealthyPipelineSafeModeRule}}: with one OPEN, one DORMANT and one CLOSED
pipeline, all fully reported, the rule must not count the DORMANT or the CLOSED
pipeline, and must pass on the OPEN one. The events carry stale copies, as the
handler's may: an OPEN copy of the DORMANT and of the CLOSED pipeline, and the
ALLOCATED copy of the OPEN pipeline, so a check on the event's own copy fails
the test as well. Without the change it fails ({{expected: 0 but was: 1}}).
With it, the {{org.apache.hadoop.hdds.scm.safemode}} unit tests together with
{{TestPipelineManagerImpl}} and {{TestPipelineActionHandler}} (108 tests) pass,
as do {{TestSCMSafeModeWithPipelineRules}} and
{{TestSafeModeCheckSubcommandHA}} on a mini cluster (8 tests), and checkstyle
is clean.
Found by TLA+ model checking and code review of the SCM safe mode rules under
HDDS-15926, on commit b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. This issue also
covers the same defect found by code review of the SCM pipeline lifecycle under
HDDS-16538, which approached it from {{PipelineReportHandler}} and the DORMANT
state. Checked against HDDS issues and apache/ozone pull requests for
duplicates before filing. Related but not duplicates: HDDS-4399 (introduced the
state independent event), HDDS-13590 (OPEN filter for the report free path
only), HDDS-11904 (datanode health check in the same method) and HDDS-11844
(open, proposes not waiting for all pipelines). 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]