schedueler: adding best fit scoring

This commit is contained in:
Armon Dadgar
2015-08-13 11:28:02 -07:00
parent 7320ae90a6
commit a4bf95e282
2 changed files with 84 additions and 1 deletions

View File

@@ -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
}

View File

@@ -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)
}
}