Skip to content

EvenScheduler idle rebalance: max.free.per.topology cap applied twice per round in DefaultScheduler path (follow-up to #8778) #8797

Description

@mwkang

Summary

In the DefaultScheduler path the idle-supervisor redistribute pass runs twice in a single scheduling round, so the per-topology nimbus.even.rebalance.max.free.per.topology cap is enforced twice — an under-assigned topology can relocate up to 2 × cap workers per round.

Introduced by #8778 (opt-in idle-supervisor rebalance). Off by default, so there is no impact unless nimbus.even.rebalance.idle.supervisor.enabled=true.

Mechanism

defaultSchedule calls redistributeOntoIdleSupervisors over the full topology set once (DefaultScheduler.java:75), then for each needs-scheduling topology calls EvenScheduler.scheduleTopologiesEvenly(new Topologies(topology), cluster) (DefaultScheduler.java:106) — and scheduleTopologiesEvenly calls redistributeOntoIdleSupervisors again on entry (EvenScheduler.java:336).

Eligibility (isIdleSupervisorAvailableForEvenRebalance) is getUsedPorts(...).isEmpty(). The first pass only marks the supervisors it actually filled; any supervisor still idle afterwards is re-selected in the second (per-topology) pass, applying the cap a second time.

Using EvenScheduler directly is unaffected (it runs scheduleTopologiesEvenly once over the full set). RAS is unaffected.

Reproduce

  • idle.supervisor.enabled=true, max.free.per.topology > 0
  • 2+ fully idle supervisors
  • an under-assigned topology whose donor supervisor still holds ≥2 of its workers
  • DefaultScheduler (or IsolationScheduler leftover delegation)

Impact

Low: off by default; excess relocation churn (throttle exceeded), not a crash or loss, and it converges over rounds. Scoped to the DefaultScheduler / EvenScheduler path.

Suggested fix

Run the redistribute pass once per round — either guard re-entry in scheduleTopologiesEvenly, or keep the single full-set pass in DefaultScheduler and skip the redistribute in the per-topology delegation. Dropping the full-set call instead would break the round-robin fairness that lets multiple topologies share idle slots, so it should be kept.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions