You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@yunikorn.apache.org by "weichen lai (Jira)" <ji...@apache.org> on 2026/10/15 13:30:00 UTC
[jira] [Resolved] (YUNIKORN-3452) Node Preemption: Fix reversed penalty scores between originator and opted-out pods
[ https://issues.apache.org/jira/browse/YUNIKORN-3452?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
weichen lai resolved YUNIKORN-3452.
-----------------------------------
Fix Version/s: 1.11.0
Resolution: Fixed
> Node Preemption: Fix reversed penalty scores between originator and opted-out pods
> ----------------------------------------------------------------------------------
>
> Key: YUNIKORN-3452
> URL: https://issues.apache.org/jira/browse/YUNIKORN-3452
> Project: Apache YuniKorn
> Issue Type: Bug
> Components: core - scheduler
> Reporter: weichen lai
> Assignee: weichen lai
> Priority: Major
> Labels: pull-request-available
> Fix For: 1.11.0
>
>
> h3. Problem
> Default preemption protects an opted-out pod more than an originator pod in two places on the node path:
> # {{sortVictimsForPreemption()}} sorts by {{allowPreemptSelf}} first and {{originator}} second, so an originator that allows preemption is preempted before an opted-out worker on the same node.
> # {{getSolutionScore()}}, used by {{checkPreemptionPredicates()}} to select a node, uses these penalties (lower is better):
> {code:go}scoreOriginator uint64 = 1 << 33
> scoreNoPreempt uint64 = 1 << 34
> {code}
> A node that needs the originator is therefore preferred over a node that needs an opted-out worker.
> Preempting an originator (driver) fails the whole application; preempting an opted-out worker affects one task.
> h3. Expected order
> Regular > Opted-out > Originator.
> * [Preemption design|https://yunikorn.apache.org/docs/next/design/preemption/]: preempting an originator "should be prevented as much as possible"; the opt-out flag is "a strong suggestion, not a guarantee" (Law 1).
> * [Quota preemption design|https://yunikorn.apache.org/docs/next/design/quota_change_enforcement_through_preemption]: "Prefer Non originator pods over originator".
> h3. Impact
> Only when the regular pods on a node are not sufficient. When it happens, the originator is preempted and the whole application fails.
> h3. Proposed change
> * Swap the values of {{scoreOriginator}} and {{scoreNoPreempt}}.
> * In {{sortVictimsForPreemption()}}, sort by {{originator}} first and {{allowPreemptSelf}} second.
> h3. Reproducer / Unit Tests
> Both tests fail on current {{master}}:
> {code:go}func TestSolutionScoring_OriginatorVsOptedOut(t *testing.T) {
> allocMap := map[string][]*Allocation{
> "node-opted-out": {allocForScore(false, false)},
> "node-originator": {allocForScore(true, true)},
> }
> solOptedOut := &predicateCheckResult{nodeID: "node-opted-out", success: true, index: 0}
> solOriginator := &predicateCheckResult{nodeID: "node-originator", success: true, index: 0}
> // An originator pod is the driver/core of an app and must be protected over an opted-out worker pod.
> // Therefore, a solution that sacrifices an opted-out pod MUST be betterThan a solution that sacrifices an originator pod.
> assert.Check(t, solOptedOut.betterThan(solOriginator, allocMap),
> "sacrificing opted-out pod should be a better solution than sacrificing originator pod")
> }
> func TestSortVictimsForPreemption(t *testing.T) {
> res := resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10})
> regularPod := createAllocation("regularPod", "app1", nodeID1, true, false, 10, false, res)
> originatorPod := createAllocation("originatorPod", "app1", nodeID1, true, true, 10, false, res)
> optedOutPod := createAllocation("optedOutPod", "app1", nodeID1, false, false, 10, false, res)
> optedOutOriginatorPod := createAllocation("optedOutOriginatorPod", "app1", nodeID1, false, true, 10, false, res)
> allocationsByNode := map[string][]*Allocation{
> nodeID1: {optedOutOriginatorPod, originatorPod, optedOutPod, regularPod},
> }
> sortVictimsForPreemption(allocationsByNode)
> allocations := allocationsByNode[nodeID1]
> assert.Equal(t, allocations[0].GetAllocationKey(), "regularPod")
> assert.Equal(t, allocations[1].GetAllocationKey(), "optedOutPod")
> assert.Equal(t, allocations[2].GetAllocationKey(), "originatorPod")
> assert.Equal(t, allocations[3].GetAllocationKey(), "optedOutOriginatorPod")
> }
> {code}
--
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