Fitness Calculators

David Gross edited this page Aug 12, 2015 · 1 revision

One way you tell the Fenzo scheduler how best to match hosts to tasks is by using fitness calculators. You can write your own, or use those that are part of Fenzo.

Contents:

  1. Introduction
    1. The Fitness “Good Enough” Function
  2. The Built-In Bin Packing fitness calculators
    1. CPU Bin Packer — cpuBinPacker
    2. Memory Bin Packer — memoryBinPacker
    3. Network Bin Packer — networkBinPacker
    4. CPU/Memory Bin Packer — cpuMemBinPacker
    5. CPU/Memory/Network Bin Packer — cpuMemNetworkBinPacker
    6. Using Constraints as Fitness Calculators
  3. Building Your Own Fitness Calculator Plugin
    1. Implementing the VMTaskFitnessCalculator Interface
    2. Combining Existing Fitness Calculator Plugins

Introduction

You incorporate a fitness calculator when you build your task scheduler by calling its builder’s .withFitnessCalculator() method. That method takes a fitness calculator plugin object, that is, one that implements the VMTaskFitnessCalculator interface.

The Fitness “Good Enough” Function

You should also implement a “good enough” function that regulates how thoroughly the task manager should search the set of hosts on offer for one that is fit for a particular task. The default “good enough” function will always search the complete list of hosts and pick the one with the highest fitness score. But this may be time consuming, and by writing a “good enough” function that adjusts its search thoroughness, you can make the system more responsive as the number of hosts and number of tasks increases.

You submit your “good enough” function by means of the .withFitnessGoodEnoughFunction() task scheduler builder method.

That function accepts as a parameter the result of your fitness calculator’s evaluation of a host for a task. That evaluation will always be a number between 0.0 (absolutely unfit) to 1.0 (perfect fit). Your function returns true if that evaluation value represents a host that is “good enough” to accept the task (and that therefore the task scheduler should go ahead and assign the task to the host and should stop searching for a better host); it returns false if the task scheduler should continue to search for a better host.

If your function returns false for every host, the task scheduler will nonetheless try to schedule the task on a host that reported the highest fitness score. That is, it will revert to the default behavior of evaluating all of the hosts and choosing the best fit among all of them.

You may want to write your function so that it is sensitive to the amount of time the task scheduler is taking to complete its scheduling allocations, and so that it adjusts the value it considers “good enough” accordingly (see How to learn how long the scheduling process is taking).

The Built-In Bin Packing Fitness Calculators

A “bin packing” fitness calculator attempts to maximize the resource use on one host before distributing tasks to another host. This reduces the number of hosts required and makes it easier to scale down clusters. There are several bin packing fitness calculator plugins that are already built-in to Fenzo:

  • CPU Bin Packer: tries to use as many of the CPUs on one host before assigning tasks to a new host
  • Memory Bin Packer: tries to use as much of the memory available on one host before assigning tasks to a new host
  • Network Bin Packer: tries to use as much of the bandwidth available to one host before assigning tasks to a new host
  • CPU/Memory Bin Packer: combines the Memory and CPU strategies listed above
  • CPU/Memory/Network Bin Packer: combines the Memory, CPU, and Network strategies listed above

These fitness calculators are available to you as attributes of the BinPackingFitnessCalculators class.

CPU Bin Packer — cpuBinPacker

The CPU bin packer returns a value indicating how close a particular host would be to utilizing its full CPU capacity if a particular task were assigned to the host. The exact calculation for cpuFitness is:

(number of CPUs already in use or assigned to tasks on the host
+ number of CPUs that would be used by the proposed task)
÷ (total number of CPUs on the host)

If a proposed task will use all of the remaining CPUs on a host, this returns 1.0, indicating that by CPU bin packing standards, the host is a perfect fit for the task. If not, it returns some positive number less than 1.0 indicating how well this task promotes a CPU bin packing strategy.

Memory Bin Packer — memoryBinPacker

The memory bin packer returns a value indicating how close a particular host would be to utilizing its full memory capacity if a particular task were assigned to the host. The exact calculation for memoryFitness is:

(amount of memory already in use or assigned to tasks on the host
+ amount of memory that would be used by the proposed task)
÷ (total amount of memory on the host)

If a proposed task will use all of the remaining memory on a host, this returns 1.0, indicating that by memory bin packing standards, the host is a perfect fit for the task. If not, it returns some positive number less than 1.0 indicating how well this task promotes a memory bin packing strategy.

Network Bin Packer — networkBinPacker

The network bin packer returns a value indicating how close a particular host would be to utilizing its full bandwidth capacity if a particular task were assigned to the host. The exact calculation for networkFitness is:

(amount of bandwidth already in use or assigned to tasks on the host
+ amount of bandwidth that would be used by the proposed task)
÷ (total amount of bandwidth available to the host)

If a proposed task will use all of the remaining bandwidth available to a host, this returns 1.0, indicating that by network bin packing standards, the host is a perfect fit for the task. If not, it returns some positive number less than 1.0 indicating how well this task promotes a network bin packing strategy.

CPU/Memory Bin Packer — cpuMemBinPacker

The CPU/memory bin packer combines the results from the CPU and memory bin packing calculations (as described above), weighting each calculation equally, in order to come up with its own fitness calculation. The exact calculation is:

cpuMemoryFitness = (cpuFitness + memoryFitness) / 2.0

CPU/Memory/Network Bin Packer — cpuMemNetworkBinPacker

The CPU/memory/network bin packer combines the results from the CPU, memory, and network bin packing calculations (as described above), weighting each calculation equally, in order to come up with its own fitness calculation. The exact calculation is:

cpuMemoryNetworkFitness = (cpuFitness + memoryFitness + networkFitness) / 3.0

Using Constraints as Fitness Calculators

You can also use a Constraint as though it were a fitness calculator by converting it into an object that implements the VMTaskFitnessCalculator interface. See Making a Constraint Soft on the Constraints page for detailed instructions on how to do this.

Building Your Own Fitness Calculator Plugin

You can build your own fitness calculator plugin either by combining existing ones or by implementing your own fitness calculation. In either case, you do so by means of an object that implements the VMTaskFitnessCalculator interface.

Implementing the VMTaskFitnessCalculator Interface

The core of the VMTaskFitnessCalculator interface is its calculateFitness() method.

This method returns a value between 0.0 and 1.0 to indicate how fit a particular task is for a particular host. 0.0 indicates no fit; 1.0 indicates a perfect fit.

This method does not have to check to see that the proposed host has sufficient resources for the proposed task. It can assume that this has already been done.

The calculateFitness() method takes the following parameters:

parameter description
taskRequest the task to evaluate for fitness with the host
targetVM the host to evaluate for fitness with the task
taskTrackerState an object that contains information about all tasks that are currently running or that have already been assigned by the task scheduler

Combining Existing Fitness Calculator Plugins

The easiest way to create a fitness calculator is to combine existing ones. Here is an example of how you might do this:

public final static VMTaskFitnessCalculator eudaimonia = new VMTaskFitnessCalculator() {
    @Override
    public String getName() {
        return "Eudaimonia";
    }
    @Override
    public double calculateFitness(TaskRequest taskRequest, VirtualMachineCurrentState targetVM, TaskTrackerState taskTrackerState) {
        double virtue = virtueCalculator.calculateFitness(taskRequest, targetVM, taskTrackerState);
        double pleasure = pleasureCalculator.calculateFitness(taskRequest, targetVM, taskTrackerState);
        return (virtue + pleasure) / 2.0;
    }
};

This fitness calculator combines the results of two other fitness calculators (virtueCalculator and pleasureCalculator) and returns a result that averages them.

As another example, you might write your own version of the built-in CPU/Memory bin packer, for example, that does not weight the CPU and memory fitness calculations equally (as the built-in version does) but weights the CPU fitness calculation as twice as important as the memory fitness calculation. You could do this with code like the following:

public final static VMTaskFitnessCalculator myCpuMemBinPacker = new VMTaskFitnessCalculator() {
    @Override
    public String getName() {
        return "myCPUAndMemoryBinPacker";
    }
    @Override
    public double calculateFitness(TaskRequest taskRequest, VirtualMachineCurrentState targetVM, TaskTrackerState taskTrackerState) {
        double cpuFitness = BinPackingFitnessCalculators.cpuBinPacker.calculateFitness(taskRequest, targetVM, taskTrackerState);
        double memoryFitness = BinPackingFitnessCalculators.memoryBinPacker.calculateFitness(taskRequest, targetVM, taskTrackerState);
        return (cpuFitness*2 + memoryFitness) / 3.0;
    }
};