mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 17:05:43 +03:00
schedueler: adding best fit scoring
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
package scheduler
|
||||
|
||||
import "github.com/hashicorp/nomad/nomad/structs"
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
)
|
||||
|
||||
// Rank is used to provide a score and various ranking metadata
|
||||
// along with a node when iterating. This state can be modified as
|
||||
@@ -108,3 +112,40 @@ func (iter *BinPackIterator) Next() *RankedNode {
|
||||
return option
|
||||
}
|
||||
}
|
||||
|
||||
// scoreFit is used to score the fit based on the Google work published here:
|
||||
// http://www.columbia.edu/~cs2035/courses/ieor4405.S13/datacenter_scheduling.ppt
|
||||
// This is equivalent to their BestFit v3
|
||||
func scoreFit(node *structs.Node, util *structs.Resources) float64 {
|
||||
// Determine the node availability
|
||||
nodeCpu := node.Resources.CPU
|
||||
if node.Reserved != nil {
|
||||
nodeCpu -= node.Reserved.CPU
|
||||
}
|
||||
nodeMem := float64(node.Resources.MemoryMB)
|
||||
if node.Reserved != nil {
|
||||
nodeMem -= float64(node.Reserved.MemoryMB)
|
||||
}
|
||||
|
||||
// Compute the free percentage
|
||||
freePctCpu := 1 - (util.CPU / nodeCpu)
|
||||
freePctRam := 1 - (float64(util.MemoryMB) / nodeMem)
|
||||
|
||||
// Total will be "maximized" the smaller the value is.
|
||||
// At 100% utilization, the total is 2, while at 0% util it is 20.
|
||||
total := math.Pow(10, freePctCpu) + math.Pow(10, freePctRam)
|
||||
|
||||
// Invert so that the "maximized" total represents a high-value
|
||||
// score. Because the floor is 20, we simply use that as an anchor.
|
||||
// This means at a perfect fit, we return 18 as the score.
|
||||
score := 20.0 - total
|
||||
|
||||
// Bound the score, just in case
|
||||
// If the score is over 18, that means we've overfit the node.
|
||||
if score > 18.0 {
|
||||
score = 18.0
|
||||
} else if score < 0 {
|
||||
score = 0
|
||||
}
|
||||
return score
|
||||
}
|
||||
|
||||
@@ -30,3 +30,45 @@ func TestFeasibleRankIterator(t *testing.T) {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreFit(t *testing.T) {
|
||||
node := mock.Node()
|
||||
node.Resources = &structs.Resources{
|
||||
CPU: 4096,
|
||||
MemoryMB: 8192,
|
||||
}
|
||||
node.Reserved = &structs.Resources{
|
||||
CPU: 2048,
|
||||
MemoryMB: 4096,
|
||||
}
|
||||
|
||||
// Test a perfect fit
|
||||
util := &structs.Resources{
|
||||
CPU: 2048,
|
||||
MemoryMB: 4096,
|
||||
}
|
||||
score := scoreFit(node, util)
|
||||
if score != 18.0 {
|
||||
t.Fatalf("bad: %v", score)
|
||||
}
|
||||
|
||||
// Test the worst fit
|
||||
util = &structs.Resources{
|
||||
CPU: 0,
|
||||
MemoryMB: 0,
|
||||
}
|
||||
score = scoreFit(node, util)
|
||||
if score != 0.0 {
|
||||
t.Fatalf("bad: %v", score)
|
||||
}
|
||||
|
||||
// Test a mid-case scenario
|
||||
util = &structs.Resources{
|
||||
CPU: 1024,
|
||||
MemoryMB: 2048,
|
||||
}
|
||||
score = scoreFit(node, util)
|
||||
if score < 10.0 || score > 16.0 {
|
||||
t.Fatalf("bad: %v", score)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user