[ 
https://issues.apache.org/jira/browse/HDDS-16906?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Siyao Meng updated HDDS-16906:
------------------------------
    Attachment: MC-7-scrub-open-pipelines-with-dead-nodes.patch

> Pipeline with a DEAD datanode stays OPEN if SCM leadership changes while the 
> node goes STALE and DEAD, and its EC container is not repaired
> -------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-16906
>                 URL: https://issues.apache.org/jira/browse/HDDS-16906
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Minor
>         Attachments: MC-7-scrub-open-pipelines-with-dead-nodes.patch, 
> TestBugMC7DeadEcPipelineMemberAfterFailovers.java
>
>
> h3. Mechanism
> Every SCM, leader or follower, runs its own node health check and fires 
> {{STALE_NODE}} and {{DEAD_NODE}} once per transition. {{StaleNodeHandler}} 
> and {{DeadNodeHandler}} close the node's pipelines through 
> {{PipelineManager.closePipeline}}, which is a Ratis request: on a follower it 
> fails with NotLeaderException. {{StaleNodeHandler}} logs "Could not finalize 
> pipeline" at INFO without the exception, {{DeadNodeHandler}} logs the 
> exception, and both drop it. No SCM fires the events again for a node that is 
> already DEAD, and nothing re-runs the handlers when an SCM becomes leader. 
> The only periodic check, {{PipelineManagerImpl.scrubPipelines}} on the 
> leader, closes an OPEN pipeline only if a member is not registered 
> (HDDS-7341); a DEAD datanode stays registered.
> So if the SCM that becomes leader saw the STALE transition while it was a 
> follower, and the same happens for the DEAD transition, no SCM closes the 
> pipeline. For RATIS/THREE pipelines the remaining datanodes can still trigger 
> the close through pipeline actions (argued, not run). A RATIS/ONE pipeline on 
> the dead datanode and EC pipelines have no such path, because no other member 
> is left or because EC datanodes are not aware of pipelines.
> h3. Trigger
> # An OPEN EC pipeline, three SCMs, and a datanode of the pipeline stops.
> # The datanode goes STALE. A follower sees it first, its handler fails, and 
> that follower becomes leader before the old leader's close has been applied.
> # The datanode goes DEAD. Again the SCM that becomes leader saw it first as a 
> follower.
> Each SCM checks node health on its own timer 
> ({{ozone.scm.heartbeat.thread.interval}}, default 3s), so each leader change 
> has to fall in a window of a few seconds around the transition, at both 
> transitions (5 minutes apart with the default stale and dead intervals). A 
> close that fails on the leader for another reason is lost the same way 
> (argued, not run).
> h3. Impact
> * The EC pipeline stays OPEN with a DEAD member. 
> {{SCMBlockProtocolServer.allocateBlock}} keeps returning it to requests that 
> do not exclude it. The client then fails over: it adds the pipeline to its 
> exclude list and asks for another one (argued from the client code, not run).
> * Its OPEN container keeps 4 of 5 replicas. {{ReplicationManager}} does not 
> reconstruct OPEN containers, and the container cannot fill, so it stays under 
> replicated until the datanode returns, an admin closes the pipeline or 
> container, or an SCM that was restarted after the node died becomes leader 
> (then the node is unregistered there and the existing scrubber rule closes 
> the pipeline).
> * In the same run, two RATIS/THREE pipelines and one RATIS/ONE pipeline with 
> the dead datanode were also still OPEN on the new leader after a scrubber 
> pass. Whether the datanodes close the RATIS/THREE ones later was not observed.
> h3. Reproduction
> PASS, unmodified source. [^TestBugMC7DeadEcPipelineMemberAfterFailovers.java] 
> ({{hadoop-ozone/integration-test}}) starts 3 SCMs, 1 OM and 5 datanodes with 
> the stale and dead intervals shortened to 6s and 40s, and writes one EC 3-2 
> key with the client. It widens the two windows with the existing 
> {{SCMNodeManager.pauseHealthCheck}} test hook on the current leader and moves 
> leadership with the admin {{transferLeadership}} RPC: followers B and C see 
> STALE, leadership moves A to B, followers A and C see DEAD, leadership moves 
> B to C. On C it then runs one scrubber pass and one ReplicationManager pass. 
> Output on the pin: the EC pipeline is OPEN with a DEAD member, its container 
> is OPEN with 4 replicas, {{allocateBlock}} for EC 3-2 returns that pipeline, 
> and the log shows the stale node handler's "Could not finalize pipeline" 
> lines and the dead node handler failing with NotLeaderException on the 
> followers. As a control, a second member stopped while C is leader gets the 
> pipeline closed. A passing test means the defect is present. With the patch 
> it fails at the first check, because the scrubber pass closes the pipeline 
> and the container moves to CLOSING.
> h3. Patch
> [^MC-7-scrub-open-pipelines-with-dead-nodes.patch], against 
> b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at 
> b9b33851b20.
> {{scrubPipelines}} also closes an OPEN pipeline that has a DEAD member, next 
> to the existing rule for unregistered members. The scrubber runs only on the 
> leader, so the close no longer depends on which SCM saw the transition, and 
> it also covers a close that failed on a stable leader. {{closePipeline}} 
> closes the pipeline's containers too, so ReplicationManager can repair them 
> once they are closed. The scrubber runs only on a leader that is ready and 
> out of safe mode. In normal operation the leader's stale or dead node handler 
> has already closed every pipeline of a DEAD node, of any type, so the rule 
> finds nothing. If such a close was lost, the scrubber does it at most one 
> scrub interval (default 5 minutes) after the node is DEAD. It does not act on 
> STALE members. Covered by {{testScrubOpenWithDeadNodes}} in the existing 
> {{TestPipelineManagerImpl}} (a STALE member keeps the pipeline open, a DEAD 
> member closes it), which fails without the change. With it the SCM pipeline 
> unit suites, {{TestSCMSafeModeManager}}, {{TestSCMNodeManager}} and 
> {{TestDeadNodeHandler}} (359 tests) and {{TestDecommissionAndMaintenance}} (9 
> tests) pass, checkstyle is clean.
> Related: HDDS-16887. If {{DeadNodeHandler}} deletes the pipeline during a 
> scrubber pass, the new close hits the {{PipelineNotFoundException}} that 
> HDDS-16887 handles (today it ends the pass, as it already can for the 
> existing rules). HDDS-16887 also wraps the loop body in {{scrubPipelines}} in 
> a {{try}} block, so the patches conflict textually and whichever lands second 
> needs a trivial rebase.
> Found by TLA+ model checking and code review of the SCM pipeline lifecycle 
> paths under HDDS-15926, on commit b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. 
> 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]

Reply via email to