Skip to content

Commit 0d57e7e

Browse files
zwForrestzengwang1
andauthored
scheduler: add new pod estimate with loadaware plugin (#1992)
Signed-off-by: zwForrest <756495135@qq.com> Co-authored-by: zengwang1 <zengwang1@xiaomi.com>
1 parent ba299ed commit 0d57e7e

File tree

2 files changed

+473
-99
lines changed

2 files changed

+473
-99
lines changed

pkg/scheduler/plugins/loadaware/load_aware.go

Lines changed: 71 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -149,112 +149,42 @@ func (p *Plugin) Filter(ctx context.Context, state *framework.CycleState, pod *c
149149
}
150150
return nil
151151
}
152-
153-
filterProfile := generateUsageThresholdsFilterProfile(node, p.args)
154-
if len(filterProfile.ProdUsageThresholds) > 0 && extension.GetPodPriorityClassWithDefault(pod) == extension.PriorityProd {
155-
status := p.filterProdUsage(node, nodeMetric, filterProfile.ProdUsageThresholds)
156-
if !status.IsSuccess() {
157-
return status
158-
}
159-
} else {
160-
var usageThresholds map[corev1.ResourceName]int64
161-
if filterProfile.AggregatedUsage != nil {
162-
usageThresholds = filterProfile.AggregatedUsage.UsageThresholds
163-
} else {
164-
usageThresholds = filterProfile.UsageThresholds
165-
}
166-
if len(usageThresholds) > 0 {
167-
status := p.filterNodeUsage(node, nodeMetric, filterProfile)
168-
if !status.IsSuccess() {
169-
return status
170-
}
171-
}
152+
if nodeMetric.Status.NodeMetric == nil {
153+
klog.Warningf("nodeMetrics(%s) should not be nil.", node.Name)
154+
return nil
172155
}
173156

174-
return nil
175-
}
176-
177-
func (p *Plugin) filterNodeUsage(node *corev1.Node, nodeMetric *slov1alpha1.NodeMetric, filterProfile *usageThresholdsFilterProfile) *framework.Status {
178-
if nodeMetric.Status.NodeMetric == nil {
157+
allocatable, err := p.estimator.EstimateNode(node)
158+
if err != nil {
159+
klog.ErrorS(err, "Estimated node allocatable failed!", "node", node.Name)
179160
return nil
180161
}
162+
filterProfile := generateUsageThresholdsFilterProfile(node, p.args)
163+
prodPod := len(filterProfile.ProdUsageThresholds) > 0 && extension.GetPodPriorityClassWithDefault(pod) == extension.PriorityProd
181164

165+
var nodeUsage *slov1alpha1.ResourceMap
182166
var usageThresholds map[corev1.ResourceName]int64
183-
if filterProfile.AggregatedUsage != nil {
184-
usageThresholds = filterProfile.AggregatedUsage.UsageThresholds
167+
if prodPod {
168+
usageThresholds = filterProfile.ProdUsageThresholds
185169
} else {
186-
usageThresholds = filterProfile.UsageThresholds
187-
}
188-
189-
for resourceName, threshold := range usageThresholds {
190-
if threshold == 0 {
191-
continue
192-
}
193-
allocatable, err := p.estimator.EstimateNode(node)
194-
if err != nil {
195-
klog.ErrorS(err, "Failed to EstimateNode", "node", node.Name)
196-
return nil
197-
}
198-
total := allocatable[resourceName]
199-
if total.IsZero() {
200-
continue
201-
}
202-
// TODO(joseph): maybe we should estimate the Pod that just be scheduled that have not reported
203-
var nodeUsage *slov1alpha1.ResourceMap
204170
if filterProfile.AggregatedUsage != nil {
205171
nodeUsage = getTargetAggregatedUsage(
206172
nodeMetric,
207173
filterProfile.AggregatedUsage.UsageAggregatedDuration,
208174
filterProfile.AggregatedUsage.UsageAggregationType,
209175
)
176+
usageThresholds = filterProfile.AggregatedUsage.UsageThresholds
210177
} else {
211178
nodeUsage = &nodeMetric.Status.NodeMetric.NodeUsage
212-
}
213-
if nodeUsage == nil {
214-
continue
215-
}
216-
217-
used := nodeUsage.ResourceList[resourceName]
218-
usage := int64(math.Round(float64(used.MilliValue()) / float64(total.MilliValue()) * 100))
219-
if usage >= threshold {
220-
reason := ErrReasonUsageExceedThreshold
221-
if filterProfile.AggregatedUsage != nil {
222-
reason = ErrReasonAggregatedUsageExceedThreshold
223-
}
224-
return framework.NewStatus(framework.Unschedulable, fmt.Sprintf(reason, resourceName))
179+
usageThresholds = filterProfile.UsageThresholds
225180
}
226181
}
227-
return nil
228-
}
229-
230-
func (p *Plugin) filterProdUsage(node *corev1.Node, nodeMetric *slov1alpha1.NodeMetric, prodUsageThresholds map[corev1.ResourceName]int64) *framework.Status {
231-
if len(nodeMetric.Status.PodsMetric) == 0 {
182+
estimatedUsed, err := p.GetEstimatedUsed(node.Name, nodeMetric, pod, nodeUsage, prodPod)
183+
if err != nil {
184+
klog.ErrorS(err, "GetEstimatedUsed failed!", "node", node.Name)
232185
return nil
233186
}
234-
235-
// TODO(joseph): maybe we should estimate the Pod that just be scheduled that have not reported
236-
podMetrics := buildPodMetricMap(p.podLister, nodeMetric, true)
237-
prodPodUsages, _ := sumPodUsages(podMetrics, nil)
238-
for resourceName, threshold := range prodUsageThresholds {
239-
if threshold == 0 {
240-
continue
241-
}
242-
allocatable, err := p.estimator.EstimateNode(node)
243-
if err != nil {
244-
klog.ErrorS(err, "Failed to EstimateNode", "node", node.Name)
245-
return nil
246-
}
247-
total := allocatable[resourceName]
248-
if total.IsZero() {
249-
continue
250-
}
251-
used := prodPodUsages[resourceName]
252-
usage := int64(math.Round(float64(used.MilliValue()) / float64(total.MilliValue()) * 100))
253-
if usage >= threshold {
254-
return framework.NewStatus(framework.Unschedulable, fmt.Sprintf(ErrReasonUsageExceedThreshold, resourceName))
255-
}
256-
}
257-
return nil
187+
return filterNodeUsage(usageThresholds, estimatedUsed, allocatable, prodPod, filterProfile)
258188
}
259189

260190
func (p *Plugin) ScoreExtensions() framework.ScoreExtensions {
@@ -291,13 +221,44 @@ func (p *Plugin) Score(ctx context.Context, state *framework.CycleState, pod *co
291221
if p.args.NodeMetricExpirationSeconds != nil && isNodeMetricExpired(nodeMetric, *p.args.NodeMetricExpirationSeconds) {
292222
return 0, nil
293223
}
224+
if nodeMetric.Status.NodeMetric == nil {
225+
klog.Warningf("nodeMetrics(%s) should not be nil.", node.Name)
226+
return 0, nil
227+
}
294228

295229
prodPod := extension.GetPodPriorityClassWithDefault(pod) == extension.PriorityProd && p.args.ScoreAccordingProdUsage
230+
var nodeUsage *slov1alpha1.ResourceMap
231+
if !prodPod {
232+
if scoreWithAggregation(p.args.Aggregated) {
233+
nodeUsage = getTargetAggregatedUsage(nodeMetric, &p.args.Aggregated.ScoreAggregatedDuration, p.args.Aggregated.ScoreAggregationType)
234+
} else {
235+
nodeUsage = &nodeMetric.Status.NodeMetric.NodeUsage
236+
}
237+
}
238+
estimatedUsed, err := p.GetEstimatedUsed(nodeName, nodeMetric, pod, nodeUsage, prodPod)
239+
if err != nil {
240+
klog.ErrorS(err, "GetEstimatedUsed failed!", "node", node.Name)
241+
return 0, nil
242+
}
243+
244+
allocatable, err := p.estimator.EstimateNode(node)
245+
if err != nil {
246+
klog.ErrorS(err, "Estimated node allocatable failed!", "node", node.Name)
247+
return 0, nil
248+
}
249+
score := loadAwareSchedulingScorer(p.args.ResourceWeights, estimatedUsed, allocatable)
250+
return score, nil
251+
}
252+
253+
func (p *Plugin) GetEstimatedUsed(nodeName string, nodeMetric *slov1alpha1.NodeMetric, pod *corev1.Pod, nodeUsage *slov1alpha1.ResourceMap, prodPod bool) (map[corev1.ResourceName]int64, error) {
254+
if nodeMetric == nil {
255+
return nil, nil
256+
}
296257
podMetrics := buildPodMetricMap(p.podLister, nodeMetric, prodPod)
297258

298259
estimatedUsed, err := p.estimator.EstimatePod(pod)
299260
if err != nil {
300-
return 0, nil
261+
return nil, err
301262
}
302263
assignedPodEstimatedUsed, estimatedPods := p.estimatedAssignedPodUsed(nodeName, nodeMetric, podMetrics, prodPod)
303264
for resourceName, value := range assignedPodEstimatedUsed {
@@ -310,12 +271,6 @@ func (p *Plugin) Score(ctx context.Context, state *framework.CycleState, pod *co
310271
}
311272
} else {
312273
if nodeMetric.Status.NodeMetric != nil {
313-
var nodeUsage *slov1alpha1.ResourceMap
314-
if scoreWithAggregation(p.args.Aggregated) {
315-
nodeUsage = getTargetAggregatedUsage(nodeMetric, &p.args.Aggregated.ScoreAggregatedDuration, p.args.Aggregated.ScoreAggregationType)
316-
} else {
317-
nodeUsage = &nodeMetric.Status.NodeMetric.NodeUsage
318-
}
319274
if nodeUsage != nil {
320275
for resourceName, quantity := range nodeUsage.ResourceList {
321276
if q := estimatedPodActualUsages[resourceName]; !q.IsZero() {
@@ -329,13 +284,30 @@ func (p *Plugin) Score(ctx context.Context, state *framework.CycleState, pod *co
329284
}
330285
}
331286
}
287+
return estimatedUsed, nil
288+
}
332289

333-
allocatable, err := p.estimator.EstimateNode(node)
334-
if err != nil {
335-
return 0, nil
290+
func filterNodeUsage(usageThresholds, estimatedUsed map[corev1.ResourceName]int64, allocatable corev1.ResourceList, prodPod bool, filterProfile *usageThresholdsFilterProfile) *framework.Status {
291+
for resourceName, value := range usageThresholds {
292+
if value == 0 {
293+
continue
294+
}
295+
total := getResourceValue(resourceName, allocatable[resourceName])
296+
if total == 0 {
297+
continue
298+
}
299+
usage := int64(math.Round(float64(estimatedUsed[resourceName]) / float64(total) * 100))
300+
if usage <= value {
301+
continue
302+
}
303+
304+
reason := ErrReasonUsageExceedThreshold
305+
if !prodPod && filterProfile.AggregatedUsage != nil {
306+
reason = ErrReasonAggregatedUsageExceedThreshold
307+
}
308+
return framework.NewStatus(framework.Unschedulable, fmt.Sprintf(reason, resourceName))
336309
}
337-
score := loadAwareSchedulingScorer(p.args.ResourceWeights, estimatedUsed, allocatable)
338-
return score, nil
310+
return nil
339311
}
340312

341313
func (p *Plugin) estimatedAssignedPodUsed(nodeName string, nodeMetric *slov1alpha1.NodeMetric, podMetrics map[string]corev1.ResourceList, filterProdPod bool) (map[corev1.ResourceName]int64, sets.String) {

0 commit comments

Comments
 (0)