You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@yunikorn.apache.org by "Hedger Lai (Jira)" <ji...@apache.org> on 2026/10/07 16:56:00 UTC

[jira] [Updated] (YUNIKORN-3449) [Core] Preemption falsely aborts and starves large asks by ignoring node available capacity in shortfall check

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

Hedger Lai updated YUNIKORN-3449:
---------------------------------
        Parent: YUNIKORN-3186
    Issue Type: Sub-task  (was: Bug)

> [Core] Preemption falsely aborts and starves large asks by ignoring node available capacity in shortfall check
> --------------------------------------------------------------------------------------------------------------
>
>                 Key: YUNIKORN-3449
>                 URL: https://issues.apache.org/jira/browse/YUNIKORN-3449
>             Project: Apache YuniKorn
>          Issue Type: Sub-task
>          Components: core - scheduler
>    Affects Versions: 1.6.0
>            Reporter: Hedger Lai
>            Assignee: Hedger Lai
>            Priority: Major
>              Labels: pull-request-available
>             Fix For: 1.11.0
>
>
> h3. Problem Summary
> In {{Preemptor.TryPreemption()}}, when selecting preemption victims on a candidate node, upstream {{tryNodes()}} and {{calculateVictimsByNode()}} evaluate victims by adding their resources to {{nodeAvailable}}:
> {code:go}
> nodeCurrentAvailable.AddTo(victim.GetAllocatedResource())
> if nodeCurrentAvailable.FitIn(p.ask.GetAllocatedResource()) && index < 0 {
>     index = len(results)
> }
> {code}
> Upstream correctly stops collecting victims once {{nodeAvailable + victims >= ask}}. That is, upstream only selects victims to cover the node's residual *deficit* ({{ask - nodeAvailable}}).
> However, downstream in {{TryPreemption()}} (lines 670-678 on master), the shortfall validation compares {{victimsTotalResource}} directly against the full ask requirement ({{p.ask.GetAllocatedResource()}}):
> {code:go}
> hasShortfall := victimsTotalResource.IsEmpty()
> if !hasShortfall {
>     for k, victimVal := range victimsTotalResource.Resources {
>         if needVal, ok := p.ask.GetAllocatedResource().Resources[k]; ok && victimVal < needVal {
>             hasShortfall = true
>             break
>         }
>     }
> }
> if hasShortfall {
>     // there is shortfall, so preemption doesn't help
>     p.ask.LogAllocationFailure(common.PreemptionShortfall, true)
>     return nil, false
> }
> {code}
> Because {{victimsTotalResource}} only accumulates victim allocations without factoring in the node's existing available capacity ({{p.nodeAvailableMap[nodeID]}}), preemption is falsely aborted whenever a candidate node has partial available capacity!
> h3. Reproduction Scenario
> Consider a node with 4 vcores capacity:
> # *Node available capacity*: 2 vcores idle ({{nodeAvailable = 2}}).
> # *Running allocation*: Pod A using 2 vcores (candidate victim).
> # *Pending Ask*: Requires 4 vcores.
> * *Upstream behavior*:
> {{calculateVictimsByNode()}} starts with 2 free vcores. It selects Pod A (2 vcores). {{nodeCurrentAvailable}} becomes {{2 + 2 = 4 vcores}}, which fits the ask. Upstream returns {{nodeVictims = [Pod A]}} (2 vcores).
> * *Downstream failure*:
> {{victimsTotalResource}} = 2 vcores.
> Downstream evaluates {{victimVal (2) < needVal (4)}} -> {{hasShortfall = true}}.
> {{TryPreemption()}} aborts with {{PreemptionShortfall}}, even though preempting Pod A would free up the 4 vcores needed to schedule the ask!
> h3. Root Cause
> In {{TryPreemption()}}, the shortfall check assumes that the total resources of all selected victims alone must equal or exceed the ask's resource requirement. It completely ignores that the selected node already contributes {{p.nodeAvailableMap[nodeID]}} towards fulfilling the ask.
> h3. Proposed Solution
> When checking for preemption shortfall on the chosen node:
> # Factor in the node's existing available capacity:
> The required physical capacity from victims on the node is {{deficit = max(0, ask - nodeAvailable)}}.
> # Ensure the shortfall check verifies whether victims satisfy the node deficit (for physical node capacity) as well as any queue headroom requirements.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@yunikorn.apache.org
For additional commands, e-mail: issues-help@yunikorn.apache.org