Compare commits

...

1 Commits

Author SHA1 Message Date
Ronan Abhamon
37a491bc0d feat(load-balancer): log events with info instead of debug
Signed-off-by: Ronan Abhamon <ronan.abhamon@vates.fr>
2021-08-04 15:56:24 +02:00
6 changed files with 41 additions and 41 deletions

View File

@ -7,6 +7,8 @@
> Users must be able to say: “Nice enhancement, I'm eager to test it” > 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 ### Bug fixes
> Users must be able to say: “I had this issue, happy to know it's fixed” > 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 > - major: if the change breaks compatibility
> >
> In case of conflict, the highest (lowest in previous list) `$version` wins. > In case of conflict, the highest (lowest in previous list) `$version` wins.
- xo-server-load-balancer minor

View File

@ -1,9 +1,9 @@
import { clone, filter, map as mapToArray } from 'lodash' import { clone, filter, map as mapToArray } from 'lodash'
import Plan from './plan' 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. // A host to optimize needs the ability to be restarted.
if (hostToOptimize.powerOnMode === '') { if (hostToOptimize.powerOnMode === '') {
debug(`Host (${hostId}) does not have a power on mode.`) log(`Host (${hostId}) does not have a power on mode.`)
continue 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 }) { async _simulate({ host, destinations, hostsAverages }) {
const { id: hostId } = host 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 vms = filter(this._getAllRunningVms(), vm => vm.$container === hostId)
const vmsAverages = await this._getVmsAverages(vms, { [host.id]: host }) const vmsAverages = await this._getVmsAverages(vms, { [host.id]: host })
for (const vm of vms) { for (const vm of vms) {
if (!vm.xenTools) { 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 return
} }
@ -118,7 +118,7 @@ export default class DensityPlan extends Plan {
// - It's necessary to maintain a dictionary of tags for each host. // - It's necessary to maintain a dictionary of tags for each host.
// - ... // - ...
if (this._antiAffinityTags.includes(tag)) { 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 return
} }
} }
@ -205,19 +205,19 @@ export default class DensityPlan extends Plan {
mapToArray(moves, move => { mapToArray(moves, move => {
const { vm, destination } = move const { vm, destination } = move
const xapiDest = this.xo.getXapi(destination) 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}).` `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) return xapiDest.migrateVm(vm._xapiId, this.xo.getXapi(destination), destination._xapiId)
}) })
) )
debug(`Shutdown Host (${fmtSrcHost}).`) log(`Shutdown Host (${fmtSrcHost}).`)
try { try {
await xapiSrc.shutdownHost(srcHost.id) await xapiSrc.shutdownHost(srcHost.id)
} catch (error) { } catch (error) {
debug(`Unable to shutdown Host (${fmtSrcHost}).`, { error }) log(`Unable to shutdown Host (${fmtSrcHost}).`, { error })
} }
} }
} }

View File

@ -5,7 +5,7 @@ import DensityPlan from './density-plan'
import PerformancePlan from './performance-plan' import PerformancePlan from './performance-plan'
import SimplePlan from './simple-plan' import SimplePlan from './simple-plan'
import { DEFAULT_CRITICAL_THRESHOLD_CPU, DEFAULT_CRITICAL_THRESHOLD_MEMORY_FREE } from './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() { _executePlans() {
debug('Execute plans!') log('Execute plans!')
return Promise.all(this._plans.map(plan => plan.execute())) return Promise.all(this._plans.map(plan => plan.execute()))
} }

View File

@ -1,9 +1,9 @@
import { filter } from 'lodash' import { filter } from 'lodash'
import Plan from './plan' 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) { function epsiEqual(a, b, epsi = 0.001) {
const absA = Math.abs(a) const absA = Math.abs(a)
@ -54,9 +54,9 @@ export default class PerformancePlan extends Plan {
for (const exceededHost of toOptimize) { for (const exceededHost of toOptimize) {
const { id } = exceededHost 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) 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. // Search bests combinations for the worst host.
await this._optimize({ await this._optimize({
@ -133,7 +133,7 @@ export default class PerformancePlan extends Plan {
} }
if (!vm.xenTools) { 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 continue
} }
@ -144,9 +144,7 @@ export default class PerformancePlan extends Plan {
// - It's necessary to maintain a dictionary of tags for each host. // - It's necessary to maintain a dictionary of tags for each host.
// - ... // - ...
if (this._antiAffinityTags.includes(tag)) { if (this._antiAffinityTags.includes(tag)) {
debug( log(`VM (${vm.id}) of Host (${exceededHost.id}) cannot be migrated. It contains anti-affinity tag '${tag}'.`)
`VM (${vm.id}) of Host (${exceededHost.id}) cannot be migrated. It contains anti-affinity tag '${tag}'.`
)
continue continue
} }
} }
@ -184,11 +182,9 @@ export default class PerformancePlan extends Plan {
(exceededAverages.cpu - vmAverages.cpu < destinationAverages.cpu + vmAverages.cpu || (exceededAverages.cpu - vmAverages.cpu < destinationAverages.cpu + vmAverages.cpu ||
exceededAverages.memoryFree + vmAverages.memory > destinationAverages.memoryFree - vmAverages.memory)) exceededAverages.memoryFree + vmAverages.memory > destinationAverages.memoryFree - vmAverages.memory))
) { ) {
debug(`Cannot migrate VM (${vm.id}) to Host (${destination.id}).`) log(`Cannot migrate VM (${vm.id}) to Host (${destination.id}).`)
debug( log(`Src Host CPU=${exceededAverages.cpu}, Dest Host CPU=${destinationAverages.cpu}, VM CPU=${vmAverages.cpu}`)
`Src Host CPU=${exceededAverages.cpu}, Dest Host CPU=${destinationAverages.cpu}, VM CPU=${vmAverages.cpu}` log(
)
debug(
`Src Host free RAM=${exceededAverages.memoryFree}, Dest Host free RAM=${destinationAverages.memoryFree}, VM used RAM=${vmAverages.memory})` `Src Host free RAM=${exceededAverages.memoryFree}, Dest Host free RAM=${destinationAverages.memoryFree}, VM used RAM=${vmAverages.memory})`
) )
continue continue
@ -200,7 +196,7 @@ export default class PerformancePlan extends Plan {
exceededAverages.memoryFree += vmAverages.memory exceededAverages.memoryFree += vmAverages.memory
destinationAverages.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}).` `Migrate VM (${vm.id} "${vm.name_label}") to Host (${destination.id} "${destination.name_label}") from Host (${fmtSrcHost}).`
) )
optimizationCount++ optimizationCount++
@ -209,6 +205,6 @@ export default class PerformancePlan extends Plan {
} }
await Promise.all(promises) await Promise.all(promises)
debug(`Performance mode: ${optimizationCount} optimizations for Host (${fmtSrcHost}).`) log(`Performance mode: ${optimizationCount} optimizations for Host (${fmtSrcHost}).`)
} }
} }

View File

@ -1,7 +1,7 @@
import { filter, groupBy, includes, isEmpty, keyBy, map as mapToArray, maxBy, minBy, size, sortBy } from 'lodash' import { filter, groupBy, includes, isEmpty, keyBy, map as mapToArray, maxBy, minBy, size, sortBy } from 'lodash'
import { inspect } from 'util' import { inspect } from 'util'
import { EXECUTION_DELAY, debug } from './utils' import { EXECUTION_DELAY, log } from './utils'
const MINUTES_OF_HISTORICAL_DATA = 30 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) 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. // Averages.
@ -145,7 +145,7 @@ export default class Plan {
// Check if a resource utilization exceeds threshold. // Check if a resource utilization exceeds threshold.
toOptimize = this._checkResourcesThresholds(hosts, avgNow) toOptimize = this._checkResourcesThresholds(hosts, avgNow)
if (toOptimize.length === 0) { if (toOptimize.length === 0) {
debug('No hosts to optimize.') log('No hosts to optimize.')
return return
} }
} }
@ -157,7 +157,7 @@ export default class Plan {
// Check in the last 30 min interval with ratio. // Check in the last 30 min interval with ratio.
toOptimize = this._checkResourcesThresholds(toOptimize, avgWithRatio) toOptimize = this._checkResourcesThresholds(toOptimize, avgWithRatio)
if (toOptimize.length === 0) { if (toOptimize.length === 0) {
debug('No hosts to optimize.') log('No hosts to optimize.')
return return
} }
} }
@ -301,14 +301,14 @@ export default class Plan {
} }
// 2. Migrate! // 2. Migrate!
debugAffinity('Try to apply anti-affinity policy.') logAffinity('Try to apply anti-affinity policy.')
debugAffinity(`VM tag count per host: ${inspect(taggedHosts, { depth: null })}.`) logAffinity(`VM tag count per host: ${inspect(taggedHosts, { depth: null })}.`)
debugAffinity(`Tags diff: ${inspect(tagsDiff, { depth: null })}.`) logAffinity(`Tags diff: ${inspect(tagsDiff, { depth: null })}.`)
const vmsAverages = await this._getVmsAverages(allVms, idToHost) const vmsAverages = await this._getVmsAverages(allVms, idToHost)
const { averages: hostsAverages } = await this._getHostStatsAverages({ hosts: allHosts }) const { averages: hostsAverages } = await this._getHostStatsAverages({ hosts: allHosts })
debugAffinity(`Hosts averages: ${inspect(hostsAverages, { depth: null })}.`) logAffinity(`Hosts averages: ${inspect(hostsAverages, { depth: null })}.`)
const promises = [] const promises = []
for (const tag in tagsDiff) { for (const tag in tagsDiff) {
@ -316,7 +316,7 @@ export default class Plan {
} }
// 3. Done! // 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) return Promise.all(promises)
} }
@ -364,11 +364,11 @@ export default class Plan {
let vm let vm
for (const destination of destinations) { for (const destination of destinations) {
destinationHost = destination 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) 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'))}.` `Tagged VM ("${tag}") candidates to migrate from host ${sourceHost.id}: ${inspect(mapToArray(vms, 'id'))}.`
) )
vm = this._getAntiAffinityVmToMigrate({ vm = this._getAntiAffinityVmToMigrate({
@ -390,7 +390,7 @@ export default class Plan {
const source = idToHost[sourceHost.id] const source = idToHost[sourceHost.id]
const destination = idToHost[destinationHost.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}").` `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 bestVariance = variance
bestVm = vm bestVm = vm
} else { } 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.`)
} }
} }
} }

View File

@ -1,6 +1,6 @@
import { createLogger } from '@xen-orchestra/log' 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. // Delay between each resources evaluation in minutes.
// Must be less than MINUTES_OF_HISTORICAL_DATA. // Must be less than MINUTES_OF_HISTORICAL_DATA.