Compare commits
1 Commits
master
...
fix-load-b
Author | SHA1 | Date | |
---|---|---|---|
|
37a491bc0d |
|
@ -7,6 +7,8 @@
|
|||
|
||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||
|
||||
- [Host/Load-balancer] Log events with `info` instead of `debug` (PR [#5870](https://github.com/vatesfr/xen-orchestra/pull/5870))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
||||
|
@ -27,3 +29,5 @@
|
|||
> - major: if the change breaks compatibility
|
||||
>
|
||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||
|
||||
- xo-server-load-balancer minor
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { clone, filter, map as mapToArray } from 'lodash'
|
||||
|
||||
import Plan from './plan'
|
||||
import { debug as debugP } from './utils'
|
||||
import { log as logP } from './utils'
|
||||
|
||||
export const debug = str => debugP(`density: ${str}`)
|
||||
export const log = str => logP(`density: ${str}`)
|
||||
|
||||
// ===================================================================
|
||||
|
||||
|
@ -48,7 +48,7 @@ export default class DensityPlan extends Plan {
|
|||
|
||||
// A host to optimize needs the ability to be restarted.
|
||||
if (hostToOptimize.powerOnMode === '') {
|
||||
debug(`Host (${hostId}) does not have a power on mode.`)
|
||||
log(`Host (${hostId}) does not have a power on mode.`)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -94,20 +94,20 @@ export default class DensityPlan extends Plan {
|
|||
}
|
||||
}
|
||||
|
||||
debug(`Density mode: ${optimizationsCount} optimizations.`)
|
||||
log(`Density mode: ${optimizationsCount} optimizations.`)
|
||||
}
|
||||
|
||||
async _simulate({ host, destinations, hostsAverages }) {
|
||||
const { id: hostId } = host
|
||||
|
||||
debug(`Try to optimize Host (${hostId}).`)
|
||||
log(`Try to optimize Host (${hostId}).`)
|
||||
|
||||
const vms = filter(this._getAllRunningVms(), vm => vm.$container === hostId)
|
||||
const vmsAverages = await this._getVmsAverages(vms, { [host.id]: host })
|
||||
|
||||
for (const vm of vms) {
|
||||
if (!vm.xenTools) {
|
||||
debug(`VM (${vm.id}) of Host (${hostId}) does not support pool migration.`)
|
||||
log(`VM (${vm.id}) of Host (${hostId}) does not support pool migration.`)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ export default class DensityPlan extends Plan {
|
|||
// - It's necessary to maintain a dictionary of tags for each host.
|
||||
// - ...
|
||||
if (this._antiAffinityTags.includes(tag)) {
|
||||
debug(`VM (${vm.id}) of Host (${hostId}) cannot be migrated. It contains anti-affinity tag '${tag}'.`)
|
||||
log(`VM (${vm.id}) of Host (${hostId}) cannot be migrated. It contains anti-affinity tag '${tag}'.`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -205,19 +205,19 @@ export default class DensityPlan extends Plan {
|
|||
mapToArray(moves, move => {
|
||||
const { vm, destination } = move
|
||||
const xapiDest = this.xo.getXapi(destination)
|
||||
debug(
|
||||
log(
|
||||
`Migrate VM (${vm.id} "${vm.name_label}") to Host (${destination.id} "${destination.name_label}") from Host (${fmtSrcHost}).`
|
||||
)
|
||||
return xapiDest.migrateVm(vm._xapiId, this.xo.getXapi(destination), destination._xapiId)
|
||||
})
|
||||
)
|
||||
|
||||
debug(`Shutdown Host (${fmtSrcHost}).`)
|
||||
log(`Shutdown Host (${fmtSrcHost}).`)
|
||||
|
||||
try {
|
||||
await xapiSrc.shutdownHost(srcHost.id)
|
||||
} catch (error) {
|
||||
debug(`Unable to shutdown Host (${fmtSrcHost}).`, { error })
|
||||
log(`Unable to shutdown Host (${fmtSrcHost}).`, { error })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import DensityPlan from './density-plan'
|
|||
import PerformancePlan from './performance-plan'
|
||||
import SimplePlan from './simple-plan'
|
||||
import { DEFAULT_CRITICAL_THRESHOLD_CPU, DEFAULT_CRITICAL_THRESHOLD_MEMORY_FREE } from './plan'
|
||||
import { EXECUTION_DELAY, debug } from './utils'
|
||||
import { EXECUTION_DELAY, log } from './utils'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
|
@ -165,7 +165,7 @@ class LoadBalancerPlugin {
|
|||
}
|
||||
|
||||
_executePlans() {
|
||||
debug('Execute plans!')
|
||||
log('Execute plans!')
|
||||
|
||||
return Promise.all(this._plans.map(plan => plan.execute()))
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { filter } from 'lodash'
|
||||
|
||||
import Plan from './plan'
|
||||
import { debug as debugP } from './utils'
|
||||
import { log as logP } from './utils'
|
||||
|
||||
export const debug = str => debugP(`performance: ${str}`)
|
||||
export const log = str => logP(`performance: ${str}`)
|
||||
|
||||
function epsiEqual(a, b, epsi = 0.001) {
|
||||
const absA = Math.abs(a)
|
||||
|
@ -54,9 +54,9 @@ export default class PerformancePlan extends Plan {
|
|||
for (const exceededHost of toOptimize) {
|
||||
const { id } = exceededHost
|
||||
|
||||
debug(`Try to optimize Host (${exceededHost.id}).`)
|
||||
log(`Try to optimize Host (${exceededHost.id}).`)
|
||||
const availableHosts = filter(hosts, host => host.id !== id)
|
||||
debug(`Available destinations: ${availableHosts.map(host => host.id)}.`)
|
||||
log(`Available destinations: ${availableHosts.map(host => host.id)}.`)
|
||||
|
||||
// Search bests combinations for the worst host.
|
||||
await this._optimize({
|
||||
|
@ -133,7 +133,7 @@ export default class PerformancePlan extends Plan {
|
|||
}
|
||||
|
||||
if (!vm.xenTools) {
|
||||
debug(`VM (${vm.id}) of Host (${exceededHost.id}) does not support pool migration.`)
|
||||
log(`VM (${vm.id}) of Host (${exceededHost.id}) does not support pool migration.`)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -144,9 +144,7 @@ export default class PerformancePlan extends Plan {
|
|||
// - It's necessary to maintain a dictionary of tags for each host.
|
||||
// - ...
|
||||
if (this._antiAffinityTags.includes(tag)) {
|
||||
debug(
|
||||
`VM (${vm.id}) of Host (${exceededHost.id}) cannot be migrated. It contains anti-affinity tag '${tag}'.`
|
||||
)
|
||||
log(`VM (${vm.id}) of Host (${exceededHost.id}) cannot be migrated. It contains anti-affinity tag '${tag}'.`)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -184,11 +182,9 @@ export default class PerformancePlan extends Plan {
|
|||
(exceededAverages.cpu - vmAverages.cpu < destinationAverages.cpu + vmAverages.cpu ||
|
||||
exceededAverages.memoryFree + vmAverages.memory > destinationAverages.memoryFree - vmAverages.memory))
|
||||
) {
|
||||
debug(`Cannot migrate VM (${vm.id}) to Host (${destination.id}).`)
|
||||
debug(
|
||||
`Src Host CPU=${exceededAverages.cpu}, Dest Host CPU=${destinationAverages.cpu}, VM CPU=${vmAverages.cpu}`
|
||||
)
|
||||
debug(
|
||||
log(`Cannot migrate VM (${vm.id}) to Host (${destination.id}).`)
|
||||
log(`Src Host CPU=${exceededAverages.cpu}, Dest Host CPU=${destinationAverages.cpu}, VM CPU=${vmAverages.cpu}`)
|
||||
log(
|
||||
`Src Host free RAM=${exceededAverages.memoryFree}, Dest Host free RAM=${destinationAverages.memoryFree}, VM used RAM=${vmAverages.memory})`
|
||||
)
|
||||
continue
|
||||
|
@ -200,7 +196,7 @@ export default class PerformancePlan extends Plan {
|
|||
exceededAverages.memoryFree += vmAverages.memory
|
||||
destinationAverages.memoryFree -= vmAverages.memory
|
||||
|
||||
debug(
|
||||
log(
|
||||
`Migrate VM (${vm.id} "${vm.name_label}") to Host (${destination.id} "${destination.name_label}") from Host (${fmtSrcHost}).`
|
||||
)
|
||||
optimizationCount++
|
||||
|
@ -209,6 +205,6 @@ export default class PerformancePlan extends Plan {
|
|||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
debug(`Performance mode: ${optimizationCount} optimizations for Host (${fmtSrcHost}).`)
|
||||
log(`Performance mode: ${optimizationCount} optimizations for Host (${fmtSrcHost}).`)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { filter, groupBy, includes, isEmpty, keyBy, map as mapToArray, maxBy, minBy, size, sortBy } from 'lodash'
|
||||
import { inspect } from 'util'
|
||||
|
||||
import { EXECUTION_DELAY, debug } from './utils'
|
||||
import { EXECUTION_DELAY, log } from './utils'
|
||||
|
||||
const MINUTES_OF_HISTORICAL_DATA = 30
|
||||
|
||||
|
@ -20,7 +20,7 @@ const LOW_THRESHOLD_MEMORY_FREE_FACTOR = 1.5
|
|||
|
||||
const numberOrDefault = (value, def) => (value >= 0 ? value : def)
|
||||
|
||||
export const debugAffinity = str => debug(`anti-affinity: ${str}`)
|
||||
export const logAffinity = str => log(`anti-affinity: ${str}`)
|
||||
|
||||
// ===================================================================
|
||||
// Averages.
|
||||
|
@ -145,7 +145,7 @@ export default class Plan {
|
|||
// Check if a resource utilization exceeds threshold.
|
||||
toOptimize = this._checkResourcesThresholds(hosts, avgNow)
|
||||
if (toOptimize.length === 0) {
|
||||
debug('No hosts to optimize.')
|
||||
log('No hosts to optimize.')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ export default class Plan {
|
|||
// Check in the last 30 min interval with ratio.
|
||||
toOptimize = this._checkResourcesThresholds(toOptimize, avgWithRatio)
|
||||
if (toOptimize.length === 0) {
|
||||
debug('No hosts to optimize.')
|
||||
log('No hosts to optimize.')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -301,14 +301,14 @@ export default class Plan {
|
|||
}
|
||||
|
||||
// 2. Migrate!
|
||||
debugAffinity('Try to apply anti-affinity policy.')
|
||||
debugAffinity(`VM tag count per host: ${inspect(taggedHosts, { depth: null })}.`)
|
||||
debugAffinity(`Tags diff: ${inspect(tagsDiff, { depth: null })}.`)
|
||||
logAffinity('Try to apply anti-affinity policy.')
|
||||
logAffinity(`VM tag count per host: ${inspect(taggedHosts, { depth: null })}.`)
|
||||
logAffinity(`Tags diff: ${inspect(tagsDiff, { depth: null })}.`)
|
||||
|
||||
const vmsAverages = await this._getVmsAverages(allVms, idToHost)
|
||||
const { averages: hostsAverages } = await this._getHostStatsAverages({ hosts: allHosts })
|
||||
|
||||
debugAffinity(`Hosts averages: ${inspect(hostsAverages, { depth: null })}.`)
|
||||
logAffinity(`Hosts averages: ${inspect(hostsAverages, { depth: null })}.`)
|
||||
|
||||
const promises = []
|
||||
for (const tag in tagsDiff) {
|
||||
|
@ -316,7 +316,7 @@ export default class Plan {
|
|||
}
|
||||
|
||||
// 3. Done!
|
||||
debugAffinity(`VM tag count per host after migration: ${inspect(taggedHosts, { depth: null })}.`)
|
||||
logAffinity(`VM tag count per host after migration: ${inspect(taggedHosts, { depth: null })}.`)
|
||||
return Promise.all(promises)
|
||||
}
|
||||
|
||||
|
@ -364,11 +364,11 @@ export default class Plan {
|
|||
let vm
|
||||
for (const destination of destinations) {
|
||||
destinationHost = destination
|
||||
debugAffinity(`Host candidate: ${sourceHost.id} -> ${destinationHost.id}.`)
|
||||
logAffinity(`Host candidate: ${sourceHost.id} -> ${destinationHost.id}.`)
|
||||
|
||||
const vms = filter(sourceVms, vm => hostsAverages[destinationHost.id].memoryFree >= vmsAverages[vm.id].memory)
|
||||
|
||||
debugAffinity(
|
||||
logAffinity(
|
||||
`Tagged VM ("${tag}") candidates to migrate from host ${sourceHost.id}: ${inspect(mapToArray(vms, 'id'))}.`
|
||||
)
|
||||
vm = this._getAntiAffinityVmToMigrate({
|
||||
|
@ -390,7 +390,7 @@ export default class Plan {
|
|||
|
||||
const source = idToHost[sourceHost.id]
|
||||
const destination = idToHost[destinationHost.id]
|
||||
debugAffinity(
|
||||
logAffinity(
|
||||
`Migrate VM (${vm.id} "${vm.name_label}") to Host (${destinationHost.id} "${destination.name_label}") from Host (${sourceHost.id} "${source.name_label}").`
|
||||
)
|
||||
|
||||
|
@ -515,7 +515,7 @@ export default class Plan {
|
|||
bestVariance = variance
|
||||
bestVm = vm
|
||||
} else {
|
||||
debugAffinity(`VM (${vm.id}) of Host (${sourceHost.id}) does not support pool migration.`)
|
||||
logAffinity(`VM (${vm.id}) of Host (${sourceHost.id}) does not support pool migration.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createLogger } from '@xen-orchestra/log'
|
||||
|
||||
export const { debug } = createLogger('xo:load-balancer')
|
||||
export const { info: log } = createLogger('xo:load-balancer')
|
||||
|
||||
// Delay between each resources evaluation in minutes.
|
||||
// Must be less than MINUTES_OF_HISTORICAL_DATA.
|
||||
|
|
Loading…
Reference in New Issue
Block a user