Skip to content

[Feature]: Queue a document ID on fault-remediation's live path, as #1627 did for cold start #1801

Description

@XRFXLP

Prerequisites

  • I searched existing issues

Code of Conduct

  • I agree to follow NVSentinel's Code of Conduct

Feature Summary

Apply the lazy-fetch pattern from #1627 to fault-remediation's live change-stream path. That PR replaced the queued item with a documentID on the cold-start path only; the live path still retains the whole decoded event, costing 7.79 KB per queued event against 0.47 KB on the path that was fixed.

Problem/Use Case

The two paths build different queue items:

reconciler.go:2019   request := reconcileRequest{documentID: documentID}   // cold start
reconciler.go:2065   request := reconcileRequest{event: &eventOut}         // live stream

EventWithToken.Event is a map[string]any of the full change-stream document, held for as long as the item sits in the workqueue.

Measured on an 11,000-node EKS cluster, same component, same cluster, same day:

Backlog source Queued events Working set Per event
cold start 200,668 41.5 -> 133.7 MB 0.47 KB
live stream 1,389,136 791 -> 9,463 MB 7.79 KB

For comparison, node-drainer holds 0.67-0.69 KB per queued event on either path, measured at 200k and 1M backlogs after #1121 made the same change there.

The practical consequence is the container limit. At 7.79 KB/event the shipped 256 Mi limit is exhausted at roughly 33,000 queued events, and 4 Gi at roughly 500,000. On the cold-start path the same limits hold 550,000 and 8.9 million.

This only bites when fault-remediation falls behind while running, since a backlog accumulated during a restart takes the cheap path. It normally dispatches in 0.08 s per node, faster than the drain stage feeding it, so the queue grows only under a burst large enough to outrun it -- which is precisely when an OOM is least welcome. That framing is an inference from the relative stage rates, not something measured by putting the component behind under production conditions.

Proposed Solution

Build the live-path item as reconcileRequest{documentID: ...} and fetch the event in the worker, exactly as the cold-start path does today. The lazy fetch already exists and is already measured: #1627 reports the added read as 0.285 ms per event at a 200k backlog and 0.558 ms at 800k.

Two details worth carrying over from #1121, which made the same change for node-drainer:

  1. Value-based DocumentID fixes deduplication as a side effect. Two enqueues of the same logical event currently create distinct pointers and bypass workqueue dedup; with a value key the workqueue marks a re-enqueued in-flight event dirty instead of adding a duplicate entry.
  2. The public enqueue interface need not change.

The trade is a datastore read per queued event against holding the document in memory. #1121 measured that as an 87% memory reduction at 50k events, and #1627 as 7.8-9.7x at 200k-800k, with reconcile latency unchanged within noise.

Component

Fault Management

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions