【Ovirt 笔记】群集策略
2017-06-15 本文已影响18人
58bc06151329
分析整理的版本为 Ovirt 3.4.5 版本。
群集策略
过滤器模块
过滤器是运行虚拟机的硬约束,是虚拟机能够运行的最小要求。
PinToHost 过滤器
new PinToHostPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
if (vm.getMigrationSupport() == MigrationSupport.PINNED_TO_HOST) {
// host has been specified for pin to host.
if(vm.getDedicatedVmForVds() != null) {
for (VDS host : hosts) {
if (host.getId().equals(vm.getDedicatedVmForVds())) {
return Arrays.asList(host);
}
}
} else {
// check pin to any (the VM should be down/ no migration allowed).
if (vm.getRunOnVds() == null) {
return hosts;
}
}
// if flow reaches here, the VM is pinned but there is no dedicated host.
// added by zb for DTCLOUD-320
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "PinToHost"); // 虚拟机需运行在指定主机
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
return new ArrayList<>();
}
return hosts;
}
- 在群集策略 Resilience 策略 中设置是否支持迁移的策略。
- 主机上运行的虚拟机都不支持迁移,并且都指定了该主机为运行的主机。
- 主机上的虚拟机没有指定运行主机,但处于非运行状态。
CPU 过滤器
new CPUPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
List<VDS> list = new ArrayList<VDS>();
for (VDS vds : hosts) {
Integer cores = SlaValidator.getInstance().getEffectiveCpuCores(vds);
if (cores != null && vm.getNumOfCpus() > cores) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_CPUS.toString());
log.debugFormat("host {0} has less cores ({1}) than vm cores ({2})",
vds.getName(),
cores,
vm.getNumOfCpus());
continue;
}
list.add(vds);
}
// added by zb for DTCLOUD-320
if (list != null && list.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "CPU");
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return list;
}
- 群集上主机的 CPU 核数需要大于等于虚拟机的 CPU 核数。
Memory 过滤器
new MemoryPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
List<VDS> list = new ArrayList<>();
// If Vm in Paused mode - no additional memory allocation needed
if (vm.getStatus() == VMStatus.Paused) {
return hosts;
}
for (VDS vds : hosts) {
if (!isVMSwapValueLegal(vds)) {
log.debugFormat("host '{0}' swap value is illegal", vds.getName());
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_SWAP.toString());
continue;
}
if (!memoryChecker.evaluate(vds, vm)) {
log.debugFormat("host '{0}' has insufficient memory to run the VM", vds.getName());
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_MEMORY.toString());
continue;
}
list.add(vds);
}
// added by zb for DTCLOUD-320
if (list == null || list.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "\u5185\u5b58"); // 内存\u5185\u5b58
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return list;
}
- 系统参数 EnableSwapCheck,默认值为 true,是否检测虚拟内存。
- 系统参数 BlockMigrationOnSwapUsagePercentage,迁移虚拟内存使用百分比。
- 当 EnableSwapCheck 为 true,检测虚拟内存,虚拟内存检测公式:((swap_total - swap_free - mem_available) * 100 / physical_mem_mb) <= Config.<Integer> getValue(ConfigValues.BlockMigrationOnSwapUsagePercentage)
- 群集上主机的剩余内存足够虚拟机内存运行。
- 检测虚拟内存和物理内存是否足够运行虚拟机。
- 主机内存的检查方法:用于调度新虚拟机的最大空闲内存 = 物理内存 × 内存优化比例(例如桌面负载200%)- 保留内存(321M)- 客户端负载(65)。
- memCommited 初始值为 65,每启动一台虚拟机 memCommited 增加该虚拟机的内存 + 65。
- 用于调度新虚拟机的最大空闲内存 - 65 >= 虚拟机的保证物理内存。
Network 过滤器
new NetworkPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
if (hosts == null || hosts.isEmpty()) {
return null;
}
List<VDS> toRemoveHostList = new ArrayList<VDS>();
List<VmNetworkInterface> vmNICs = getVmNetworkInterfaceDao().getAllForVm(vm.getId());
Guid clusterId = hosts.get(0).getVdsGroupId();
List<Network> clusterNetworks = getNetworkDAO().getAllForCluster(clusterId);
Map<String, Network> networksByName = Entities.entitiesByName(clusterNetworks);
Map<Guid, List<String>> hostNics = getInterfaceDAO().getHostNetworksByCluster(clusterId);
Network displayNetwork = NetworkUtils.getDisplayNetwork(clusterNetworks);
Map<Guid, VdsNetworkInterface> hostDisplayNics = getDisplayNics(displayNetwork);
for (VDS host : hosts) {
ValidationResult result =
validateRequiredNetworksAvailable(host,
vm,
vmNICs,
displayNetwork,
networksByName,
hostNics.get(host.getId()),
hostDisplayNics.get(host.getId()));
if (!result.isValid()) {
messages.add(result.getMessage().name());
if (result.getVariableReplacements() != null) {
messages.addAll(result.getVariableReplacements());
}
toRemoveHostList.add(host);
}
}
hosts.removeAll(toRemoveHostList);
// added by zb for DTCLOUD-320
if (hosts == null || hosts.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "\u7f51\u7edc"); //网络
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hosts;
}
- OnlyRequiredNetworksMandatoryForVdsSelection 系统参数是否必须网络,默认值为:false。
- 如果虚拟机的 网络接口 未配置或者没有生效地配置,会选择群集上所有的主机。
- 网络接口是 已插入,并且虚拟机网络接口的 网络名称 不为空并在群集的网络中是 必需的,并且虚拟机的网络不是 外部供应商 提供的,当虚拟机的网络接口的 网络名称 与群集上主机网络接口的 网络名称 相等,则选择该主机,不相等则过滤掉。
- 如果 OnlyRequiredNetworksMandatoryForVdsSelection 设置为 false,除了 必需的 网络,还要考虑 显示网络,一个群集中 显示网络 只有一个,选择群集上 显示网络 的主机,并且该主机 显示网络 的接口协议不能是 None(node 上报,engine 无法设置)。
HA 过滤器
new HostedEngineHAClusterFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
// The filter is relevant only for Hosted Engine VM
if (vm.isHostedEngine()) {
List<VDS> hostsToRunOn = new ArrayList<VDS>();
for (VDS host : hosts) {
int haScore = host.getHighlyAvailableScore();
if (haScore > 0) {
hostsToRunOn.add(host);
log.debugFormat("Host {0} wasn't filtered out as it has a score of {1}",
host.getName(),
haScore);
} else {
log.debugFormat("Host {0} was filtered out as it doesn't have a positive score (the score is {1})", host.getName(), haScore);
}
}
if (hostsToRunOn.isEmpty()) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_NO_HA_VDS.name());
// added by zb for DTCLOUD-320
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "HA");
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hostsToRunOn;
} else {
return hosts;
}
}
- 如果有非本群集的虚拟机迁移过来,则取 高可用性分数 大于 0 的主机。
CPU-Level 过滤器
new CpuLevelFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
boolean filteredOutHosts = false;
if (StringUtils.isNotEmpty(vm.getCpuName())) {
List<VDS> hostsToRunOn = new ArrayList<VDS>();
for (VDS host : hosts) {
String hostCpuName = CpuFlagsManagerHandler.FindMaxServerCpuByFlags(host.getCpuFlags(), host.getVdsGroupCompatibilityVersion()).getCpuName();
if (StringUtils.isNotEmpty(hostCpuName)) {
int compareResult = CpuFlagsManagerHandler.compareCpuLevels(vm.getCpuName(), hostCpuName, vm.getVdsGroupCompatibilityVersion());
if (compareResult <= 0) {
hostsToRunOn.add(host);
log.debugFormat("Host {0} wasn't filtered out as it has a CPU level ({1}) which is higher or equal than the CPU level the VM was run with ({2})",
host.getName(),
hostCpuName,
vm.getCpuName());
} else {
log.debugFormat("Host {0} was filtered out as it has a CPU level ({1}) which is lower than the CPU level the VM was run with ({2})",
host.getName(),
hostCpuName,
vm.getCpuName());
filteredOutHosts = true;
}
}
}
if (filteredOutHosts) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_CPU_LEVEL.toString());
}
// added by zb for DTCLOUD-320
if (hostsToRunOn == null || hostsToRunOn.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "CPU\u7ea7\u522b"); //CPU-Level
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hostsToRunOn;
} else {
return hosts;
}
}
- 群集上主机的 CPU 级别必须大于等于 虚拟机的 CPU 级别。
VmAffinityGroups 过滤器
new VmAffinityFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
return getAcceptableHosts(true, hosts, vm, messages);
}
- 存在关系组,则选择关系组中与虚拟机相关的、强制且为积极的主机,没有关系组则返回所有主机。
权重模块
权重代表对运行虚拟机的软约束,策略使用到的权重模块分数最终会被统计,最低权重值的主机会被调度程序选择。如果 群集 的群集策略中选中 为速度进行优化,且多于 10 个请求时跳过权重计算,否则将进行权重计算,权重计算会使用 配置 中的 Weights模块 权重模块。
- 权重值(如果当前没有此主机的记录,则该主机权重值为 0 最优先,否则为各个 权重模块 的 factor(因子) × score(分数) 相加)
- 其中 分数 由各 权重模块 计算得出,每个 权重模块 都有相应的 分数 算法,因子 默认为 1。
- 因子,可以通过 engine 界面,配置 → Weights 模块的 “+” 操作设置。
- 主机的权重值越大,优先级越小,因子 越大,分数 所占的权重比例越大,如果权重模块的 分数大于 0 则会相应的拉低主机的优先级。
- 最大权重分数,来自系统参数 MaxSchedulerWeight 的值,默认值为 1000。
公用的权重模块
策略 None、Power_Saving、Evenly_Distributed、Vm_Evenly_Distributed,共同使用的权重模块有以下几种:
HA 权重模块的分数算法
new HostedEngineHAClusterWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
boolean isHostedEngine = vm.isHostedEngine();
if (isHostedEngine) {
// If the max HA score is higher than the max weight, then we normalize. Otherwise the ratio is 1, keeping the value as is
float ratio = MAXIMUM_HA_SCORE > MaxSchedulerWeight ? ((float) MaxSchedulerWeight / MAXIMUM_HA_SCORE) : 1;
for (VDS host : hosts) {
scores.add(new Pair<Guid, Integer>(host.getId(), MaxSchedulerWeight - Math.round(host.getHighlyAvailableScore() * ratio)));
}
} else {
fillDefaultScores(hosts, scores);
}
return scores;
}
- 最大的 HA 得分,系统默认为 2400。
- 如果运行的虚拟机是一个 HostedEngine,主机分数:MaxSchedulerWeight - Math.round(host.getHighlyAvailableScore() * ratio)。
- 比率(MAXIMUM_HA_SCORE > MaxSchedulerWeight ? ((float) MaxSchedulerWeight / MAXIMUM_HA_SCORE) : 1)。
- 虚拟机是 HostedEngine,优先选择高可用分数最高的主机;否则,所有主机优先级一致。
VmAffinityGroups 权重模块的分数算法
new VmAffinityWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
// reuse filter functionality with soft constraint
List<VDS> acceptableHostsList =
VmAffinityFilterPolicyUnit.getAcceptableHosts(false,
hosts,
vm,
new ArrayList<String>());
Map<Guid, VDS> acceptableHostsMap = new HashMap<Guid, VDS>();
if (acceptableHostsList != null) {
for (VDS acceptableHost : acceptableHostsList) {
acceptableHostsMap.put(acceptableHost.getId(), acceptableHost);
}
}
List<Pair<Guid, Integer>> retList = new ArrayList<Pair<Guid, Integer>>();
int score;
for (VDS host : hosts) {
score = 1;
if (!acceptableHostsMap.containsKey(host.getId())) {
score = MaxSchedulerWeight;
}
retList.add(new Pair<Guid, Integer>(host.getId(), score));
}
return retList;
}
关系组属性 | 说明 |
---|---|
Positive | 虚拟机要运行在同一主机上 |
Negative | 虚拟机要运行在不同的主机上 |
Hard | 不考虑外部条件强制执行 |
Soft | 在外部条件允许的条件下尽量执行 |
- 定义 Soft 和 Positive 类型的关系组。
- 获取组内 运行状态 的虚拟机所在的主机,并且要求这个主机中的所有虚拟机都不能属于 Negative 类型的其他关系组。
- 定义满足以上条件的主机为可接受的。
- 进行权重分数计算的主机如果不属于可接受的主机,则分数为 最大权重分数,否则分数为 1。
- 关系组为空,则所有主机分数为 1。
- 没有关系组的主机或者属于可接受的主机,则分数为 1,否则为 最大权重分数。
OptimalForHaReservation 权重模块的分数算法
new HaReservationWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
log.info("Started HA reservation scoring method");
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
Map<Guid, Integer> hostsHaVmCount = new HashMap<Guid, Integer>();
// If the vm is not HA or the cluster is not marked as HA Reservation set default score.
VDSGroup vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
if (!vm.isAutoStartup() || !vdsGroup.supportsHaReservation()) {
fillDefaultScores(hosts, scores);
} else {
// Use a single call to the DB to retrieve all VM in the Cluster and map them by Host id
Map<Guid, List<VM>> hostId2HaVmMapping = HaReservationHandling.mapHaVmToHostByCluster(vdsGroup.getId());
int maxCount = 0;
for (VDS host : hosts) {
int count = 0;
if (hostId2HaVmMapping.containsKey(host.getId())) {
count = hostId2HaVmMapping.get(host.getId()).size();
}
maxCount = (maxCount < count) ? count : maxCount;
hostsHaVmCount.put(host.getId(), count);
}
// Fit count to scale of 0 to RATIO_FACTOR
if (maxCount > 0) {
for (VDS host : hosts) {
int fittedCount =
Math.round(hostsHaVmCount.get(host.getId()).floatValue() / maxCount * RATIO_FACTOR);
hostsHaVmCount.put(host.getId(), fittedCount);
}
}
// Get scale down param
Integer scaleDownParameter = 1;
if (parameters.get("ScaleDown") != null) {
scaleDownParameter = Integer.parseInt(parameters.get("ScaleDown"));
} else {
scaleDownParameter = Config.<Integer> getValue(ConfigValues.ScaleDownForHaReservation);
}
// Set the score pairs
for (VDS host : hosts) {
// Scale down if needed
int haCount = hostsHaVmCount.get(host.getId());
haCount = (int) Math.ceil(haCount / scaleDownParameter.floatValue());
scores.add(new Pair<Guid, Integer>(host.getId(), haCount));
log.infoFormat("Score for host:{0} is {1}", host.getName(), haCount);
}
}
return scores;
}
- 如果主机所在群集没有设置启用 HA Reservation 或者启动的虚拟机没有设置 高度可用,那么主机权重分数为:0。
- 相对反计算出各主机包含的 高度可用 虚拟机数量。
- 根据虚拟机数量,计算出各主机对应的 hostsHaVmCount。
int maxCount = 0;
for (VDS host : hosts) {
int count = 0;
if (hostId2HaVmMapping.containsKey(host.getId())) {
count = hostId2HaVmMapping.get(host.getId()).size();
}
maxCount = (maxCount < count) ? count : maxCount;
hostsHaVmCount.put(host.getId(), count);
}
// Fit count to scale of 0 to RATIO_FACTOR
if (maxCount > 0) {
for (VDS host : hosts) {
int fittedCount =
Math.round(hostsHaVmCount.get(host.getId()).floatValue() / maxCount * RATIO_FACTOR);
hostsHaVmCount.put(host.getId(), fittedCount);
}
}
- 当前主机上的高可用虚拟机数 ÷ 所有主机中虚拟机最大数 × RATIO_FACTOR(默认值 100)。
- 如果没有在界面群集策略的属性值中设置 scaleDown 参数,就设置为系统属性 ScaleDownForHaReservation 的值,默认为 1。
- 根据 scaleDown 参数和 hostsHaVmCount,计算出最终的权重分数:Math.ceil(haCount / scaleDownParameter.floatValue())
- 虚拟机如果 高可用,并且群集支持 HaReservation,则优先选择虚拟机运行少的主机。
不同的权重模块
OptimalForEvenDistribution 权重模块的分数算法(主要应用于 Evenly_Distributed 群集策略)
new EvenDistributionWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
VDSGroup vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
boolean countThreadsAsCores = vdsGroup != null ? vdsGroup.getCountThreadsAsCores() : false;
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
scores.add(new Pair<Guid, Integer>(vds.getId(), calcEvenDistributionScore(vds, vm, countThreadsAsCores)));
}
return scores;
}
return (hostCpu / vcpu) + (pendingVcpus + vm.getNumOfCpus() + spmCpu) / hostCores;
- 权重分数等于 (主机的 CPU 使用百分比 ÷ 虚拟 CPU 消耗百分比) + (主机预计使用的虚拟 CPU 总数 + 虚拟机 CPU 数量 + SPM 消耗 CPU 数量) / 主机实际生效的 CPU 数量
- 如果设置了 将线程用作内核,那么主机实际生效的 CPU 数量等于 CPU 线程数量,否则等于 CPU 核数。
public static Integer getEffectiveCpuCores(VDS vds, boolean countThreadsAsCores) {
if (vds.getCpuThreads() != null
&& countThreadsAsCores) {
return vds.getCpuThreads();
} else {
return vds.getCpuCores();
}
}
- CPU 占用少的、非 SPM 的主机优先级高。
None 权重模块的分数算法(主要应用于 None 群集策略)
new NoneWeightPolicyUnit(policyUnit);
@Override
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
return super.score(hosts, vm, parameters);
}
- 沿用了 OptimalForEvenDistribution 权重模块的计算方法。
- CPU 占用少的、非 SPM 的主机优先级高。
OptimalForPowerSaving 权重模块的分数算法(主要应用于 Power_Saving 群集策略)
new PowerSavingWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
VDSGroup vdsGroup = null;
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
int score = MaxSchedulerWeight - 1;
if (vds.getVmCount() > 0) {
if (vdsGroup == null) {
vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
}
score -=
calcEvenDistributionScore(vds, vm, vdsGroup != null ? vdsGroup.getCountThreadsAsCores() : false);
}
scores.add(new Pair<Guid, Integer>(vds.getId(), score));
}
return scores;
}
- 分数(最大权重分数 - 1 - Evenly_Distributed 方法计算出的分数)
- 与 Evenly_Distributed 算法相反,虚拟机会运行得更加集中,并且会优先选择 SPM。
OptimalForEvenGuestDistribution 权重模块的分数算法(主要应用于 VM_Evenly_Distributed 群集策略)
new EvenGuestDistributionWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
scores.add(new Pair<Guid, Integer>(vds.getId(), calcEvenGuestDistributionScore(vds, parameters)));
}
return scores;
}
private int getOccupiedVmSlots(VDS vds, Map<String, String> parameters) {
int occupiedSlots = vds.getVmActive();
final int SPMVMCountGrace = NumberUtils.toInt(parameters.get("SpmVmGrace"),
spmVmGrace);
if (vds.isSpm())
occupiedSlots += SPMVMCountGrace;
return occupiedSlots;
}
private int calcEvenGuestDistributionScore(VDS vds, Map<String, String> parameters) {
return Math.max(0, getOccupiedVmSlots(vds, parameters));
}
- 作为 SPM 主机,比其他主机运行的虚拟机少多少,来自系统参数 SpmVmGraceForEvenGuestDistribute,默认值为 5。
- 非 SPM 主机,分数为主机上激活虚拟机数量总和。SPM 主机,分数(激活虚拟机数量总和 + 预留的用于分配的虚拟机数量)。
- 非 SPM 优先 SPM 主机,虚拟机运行少 的主机优先 虚拟机运行多 的主机。**
负载平衡器
None 负载平衡器
new NoneBalancePolicyUnit(policyUnit);
@Override
public Pair<List<Guid>, Guid> balance(VDSGroup cluster,
List<VDS> hosts,
Map<String, String> parameters,
ArrayList<String> messages) {
return null;
}
- 新的虚拟机会在群集中的一个,把策略值设置为 None 将不允许在主机间进行 负载 和电源共享。这是系统的默认值。
- None 策略的 balance 没有定义具体内容,所以虚拟机在启动后会一直在一个主机上。
OptimalForPowerSaving 负载平衡器
只在一部分主机中分配 CPU 处理负载,这可以为其它主机节省能源消耗。如果主机上的 CPU 负载处于低使用率状态,并且处于这个状态的时间超过了预先定义的时间,这个主机上的虚拟机将被迁移到其它主机上,并在迁移后关闭这个主机。如果一个主机的利用率已经达到了设置的最高值,新加入到这个主机的虚拟机将不会被启动。
参数 | 说明 |
---|---|
CpuOverCommitDurationMinutes | 在群集策略起作用前,一个主机可以在 CPU 负载超过利用率中所设置的值的情况下运行的 最长 时间(以分钟为单位)。通过这个设置,可以避免因为暂时的高 CPU 负载所带来的不必要的虚拟机迁移操作,默认获取系统参数 CpuOverCommitDurationMinutes 的值,默认值是 2 分钟。 |
HighUtilization | 最高利用率,一个百分比值,默认获取系统参数 LowUtilizationForPowerSave 的值,默认值为 10。 |
LowUtilization | 最低利用率,一个百分比值,默认获取系统参数 HighUtilizationForPowerSave 的值,默认值为 6。 |
return new PowerSavingBalancePolicyUnit(policyUnit);
public Pair<List<Guid>, Guid> balance(VDSGroup cluster,
List<VDS> hosts,
Map<String, String> parameters,
ArrayList<String> messages) {
final Pair<List<Guid>, Guid> migrationRule = super.balance(cluster, hosts, parameters, messages);
List<VDS> allHosts = DbFacade.getInstance().getVdsDao().getAllForVdsGroup(cluster.getId());
List<VDS> emptyHosts = new ArrayList<>();
List<VDS> maintenanceHosts = new ArrayList<>();
List<VDS> downHosts = new ArrayList<>();
getHostLists(allHosts, parameters, emptyHosts, maintenanceHosts, downHosts);
Pair<VDS, VDSStatus> action = evaluatePowerManagementSituation(
cluster,
downHosts,
maintenanceHosts,
emptyHosts,
parameters);
if (action != null) {
processPmAction(action);
}
return migrationRule;
}
- 系统参数 HostsInReserve 主机储备必须配置为大于 0,才能通过电源管理自动启动主机。
- 系统参数 EnableAutomaticHostPowerManagement 必须设置为 true,才能进行自动电源管理,非 SPM 主机会自动切换至维护状态,然后关机。
- 系统参数 UtilizationThresholdInPercent 利用率的门槛值,默认值为 80。
- 系统参数 VcpuConsumptionPercentage,虚拟 CPU 消耗百分比,默认值为 10。
- 主机的 CPU 利用率 超过了 highVdsCount 并达到了 设定的时间(CpuOverCommitDurationMinutes),引擎对该主机上的虚拟机进行迁移,将虚拟机迁移到 CPU 利用率最低 的主机上,该动作重复执行,直到主机的 CPU 利用率 小于 highVdsCount。
- highVdsCount(Math.min(Config.<Integer> getValue(ConfigValues.UtilizationThresholdInPercent) * highUtilization / 100, highUtilization - Config.<Integer> getValue(ConfigValues.VcpuConsumptionPercentage)))。取(利用率的临界值 × 最高利用率 ÷ 100)和(最高利用率 - 虚拟 CPU 消耗百分比)的更小值。
- 当主机的 CPU 利用率 低于了设定的 最低利用率(LowUtilization) 并达到了 设定的时间,引擎会在满足 最高利用率 条件的情况下将虚拟机迁移到其他主机上,虚拟机全部迁移后,引擎会关闭该主机。
- 群集中所有主机 CPU 利用率 都低于 最低利用率 的时候,不会进行迁移。
OptimalForEvenDistribution 负载平衡器
new EvenDistributionBalancePolicyUnit(policyUnit);
- 新的虚拟机会运行在 CPU利用率 最低的主机上。
- 主机的 CPU 利用率 超过了 highVdsCount 并达到了 设定的时间(CpuOverCommitDurationMinutes),引擎对该主机上的虚拟机进行迁移,将虚拟机迁移到 CPU 利用率最低 的主机上,该动作重复执行,直到主机的 CPU 利用率 小于 highVdsCount。
- highVdsCount(Math.min(Config.<Integer> getValue(ConfigValues.UtilizationThresholdInPercent) * highUtilization / 100, highUtilization - Config.<Integer> getValue(ConfigValues.VcpuConsumptionPercentage)))。取(利用率的临界值 × 最高利用率 ÷ 100)和(最高利用率 - 虚拟 CPU 消耗百分比)的更小值。
- 当主机的 CPU 利用率 低于了设定的 最低利用率(LowUtilization) 并达到了 设定的时间,引擎会在满足 最高利用率 条件的情况下将虚拟机迁移到其他主机上,虚拟机全部迁移后,引擎会关闭该主机。
OptimalForEvenGuestDistribution 负载平衡器
new EvenGuestDistributionBalancePolicyUnit(policyUnit);
参数 | 说明 |
---|---|
SpmVmGrace | SPM 该变量定义了 SPM 主机究竟比其他主机运行的虚拟机少多少,默认获取系统参数 SpmVmGraceForEvenGuestDistribute 的值,默认值为 5。 |
MigrationThreshold | 在虚拟机从主机迁移之前,定义一个缓冲区。它最大限度的包容了最高利用率主机和最低利用率主机在虚拟机数量上的不同。当在群集中的每台主机都有一个虚拟机计数在值内时,该群集是均衡的,默认系统参数 MigrationThresholdForEvenGuestDistribute 的值,默认值为:5。 |
HighVmCount | 设置可在每台服务器运行虚拟机的最大数目。超过此限制限定服务器重载,默认系统参数 HighVmCountForEvenGuestDistribute 的值,默认值为:10 |
- 当某个主机上运行的虚拟机数量超过 过载值(HighVmCount),并且 最高利用率 主机上的虚拟机数量和 最低利用率 主机上的虚拟机数量的差值大于 容忍度值(MigrationThreshold),引擎会将该主机上的虚拟机迁移到最低利用率的主机上。
分析整理的版本为 Ovirt 3.4.5 版本。
群集策略
过滤器模块
过滤器是运行虚拟机的硬约束,是虚拟机能够运行的最小要求。
PinToHost 过滤器
new PinToHostPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
if (vm.getMigrationSupport() == MigrationSupport.PINNED_TO_HOST) {
// host has been specified for pin to host.
if(vm.getDedicatedVmForVds() != null) {
for (VDS host : hosts) {
if (host.getId().equals(vm.getDedicatedVmForVds())) {
return Arrays.asList(host);
}
}
} else {
// check pin to any (the VM should be down/ no migration allowed).
if (vm.getRunOnVds() == null) {
return hosts;
}
}
// if flow reaches here, the VM is pinned but there is no dedicated host.
// added by zb for DTCLOUD-320
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "PinToHost"); // 虚拟机需运行在指定主机
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
return new ArrayList<>();
}
return hosts;
}
- 在群集策略 Resilience策略 中设置是否支持迁移的策略。
- 主机上运行的虚拟机都不支持迁移,并且都指定了该主机为运行的主机。
- 主机上的虚拟机没有指定运行主机,但处于非运行状态。
CPU 过滤器
new CPUPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
List<VDS> list = new ArrayList<VDS>();
for (VDS vds : hosts) {
Integer cores = SlaValidator.getInstance().getEffectiveCpuCores(vds);
if (cores != null && vm.getNumOfCpus() > cores) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_CPUS.toString());
log.debugFormat("host {0} has less cores ({1}) than vm cores ({2})",
vds.getName(),
cores,
vm.getNumOfCpus());
continue;
}
list.add(vds);
}
// added by zb for DTCLOUD-320
if (list != null && list.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "CPU");
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return list;
}
- 群集上主机的 CPU 核数需要大于等于虚拟机的 CPU 核数。
Memory 过滤器
new MemoryPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
List<VDS> list = new ArrayList<>();
// If Vm in Paused mode - no additional memory allocation needed
if (vm.getStatus() == VMStatus.Paused) {
return hosts;
}
for (VDS vds : hosts) {
if (!isVMSwapValueLegal(vds)) {
log.debugFormat("host '{0}' swap value is illegal", vds.getName());
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_SWAP.toString());
continue;
}
if (!memoryChecker.evaluate(vds, vm)) {
log.debugFormat("host '{0}' has insufficient memory to run the VM", vds.getName());
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_MEMORY.toString());
continue;
}
list.add(vds);
}
// added by zb for DTCLOUD-320
if (list == null || list.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "\u5185\u5b58"); // 内存\u5185\u5b58
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return list;
}
- 系统参数 EnableSwapCheck,默认值为 true,是否检测虚拟内存。
- 系统参数 BlockMigrationOnSwapUsagePercentage,迁移虚拟内存使用百分比。
- 当 EnableSwapCheck 为 true,检测虚拟内存,虚拟内存检测公式:((swap_total - swap_free - mem_available) * 100 / physical_mem_mb) <= Config
.<Integer> getValue(ConfigValues.BlockMigrationOnSwapUsagePercentage) - 群集上主机的剩余内存足够虚拟机内存运行。
- 检测虚拟内存和物理内存是否足够运行虚拟机。
Network 过滤器
new NetworkPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
if (hosts == null || hosts.isEmpty()) {
return null;
}
List<VDS> toRemoveHostList = new ArrayList<VDS>();
List<VmNetworkInterface> vmNICs = getVmNetworkInterfaceDao().getAllForVm(vm.getId());
Guid clusterId = hosts.get(0).getVdsGroupId();
List<Network> clusterNetworks = getNetworkDAO().getAllForCluster(clusterId);
Map<String, Network> networksByName = Entities.entitiesByName(clusterNetworks);
Map<Guid, List<String>> hostNics = getInterfaceDAO().getHostNetworksByCluster(clusterId);
Network displayNetwork = NetworkUtils.getDisplayNetwork(clusterNetworks);
Map<Guid, VdsNetworkInterface> hostDisplayNics = getDisplayNics(displayNetwork);
for (VDS host : hosts) {
ValidationResult result =
validateRequiredNetworksAvailable(host,
vm,
vmNICs,
displayNetwork,
networksByName,
hostNics.get(host.getId()),
hostDisplayNics.get(host.getId()));
if (!result.isValid()) {
messages.add(result.getMessage().name());
if (result.getVariableReplacements() != null) {
messages.addAll(result.getVariableReplacements());
}
toRemoveHostList.add(host);
}
}
hosts.removeAll(toRemoveHostList);
// added by zb for DTCLOUD-320
if (hosts == null || hosts.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "\u7f51\u7edc"); //网络
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hosts;
}
- 过滤去除群集以及网络中没有的主机。
- 主机可以有多个网卡,但是虚拟机的网卡如果和主机不对应,无法运行,不能运行虚拟机的主机都被过滤掉。
- 主机如果设置了必须网络,也会进行检测。
HA 过滤器
new HostedEngineHAClusterFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
// The filter is relevant only for Hosted Engine VM
if (vm.isHostedEngine()) {
List<VDS> hostsToRunOn = new ArrayList<VDS>();
for (VDS host : hosts) {
int haScore = host.getHighlyAvailableScore();
if (haScore > 0) {
hostsToRunOn.add(host);
log.debugFormat("Host {0} wasn't filtered out as it has a score of {1}",
host.getName(),
haScore);
} else {
log.debugFormat("Host {0} was filtered out as it doesn't have a positive score (the score is {1})", host.getName(), haScore);
}
}
if (hostsToRunOn.isEmpty()) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_NO_HA_VDS.name());
// added by zb for DTCLOUD-320
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "HA");
AuditLogDirector.log(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hostsToRunOn;
} else {
return hosts;
}
}
- 如果有非本群集的虚拟机迁移过来,则取 高可用性分数 大于 0 的主机。
CPU-Level 过滤器
new CpuLevelFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
boolean filteredOutHosts = false;
if (StringUtils.isNotEmpty(vm.getCpuName())) {
List<VDS> hostsToRunOn = new ArrayList<VDS>();
for (VDS host : hosts) {
String hostCpuName = CpuFlagsManagerHandler.FindMaxServerCpuByFlags(host.getCpuFlags(), host.getVdsGroupCompatibilityVersion()).getCpuName();
if (StringUtils.isNotEmpty(hostCpuName)) {
int compareResult = CpuFlagsManagerHandler.compareCpuLevels(vm.getCpuName(), hostCpuName, vm.getVdsGroupCompatibilityVersion());
if (compareResult <= 0) {
hostsToRunOn.add(host);
log.debugFormat("Host {0} wasn't filtered out as it has a CPU level ({1}) which is higher or equal than the CPU level the VM was run with ({2})",
host.getName(),
hostCpuName,
vm.getCpuName());
} else {
log.debugFormat("Host {0} was filtered out as it has a CPU level ({1}) which is lower than the CPU level the VM was run with ({2})",
host.getName(),
hostCpuName,
vm.getCpuName());
filteredOutHosts = true;
}
}
}
if (filteredOutHosts) {
messages.add(VdcBllMessages.ACTION_TYPE_FAILED_VDS_VM_CPU_LEVEL.toString());
}
// added by zb for DTCLOUD-320
if (hostsToRunOn == null || hostsToRunOn.size() == 0) {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("policyName", "CPU\u7ea7\u522b"); //CPU-Level
AlertDirector.Alert(logable, AuditLogType.NO_HOSTS_SATISFY_POLICY);
}
return hostsToRunOn;
} else {
return hosts;
}
}
- 群集上主机的 CPU 级别必须大于等于 虚拟机的 CPU 级别。
VmAffinityGroups 过滤器
new VmAffinityFilterPolicyUnit(policyUnit);
public List<VDS> filter(List<VDS> hosts, VM vm, Map<String, String> parameters, List<String> messages) {
return getAcceptableHosts(true, hosts, vm, messages);
}
- 存在关系组,则选择关系组中与虚拟机相关的、强制且为积极的主机,没有关系组则返回所有主机。
权重模块
权重代表对运行虚拟机的软约束,策略使用到的权重模块分数最终会被统计,最低权重值的主机会被调度程序选择。
- 权重值(如果当前没有此主机的记录,则该主机权重值为 0 最优先,否则为各个 权重模块 的 factor(因子) × score(分数) 相加)
- 其中 分数 由各 权重模块 计算得出,每个 权重模块 都有相应的 分数 算法,因子 默认为 1。
- 因子,可以通过 engine 界面,配置 → Weights 模块的 “+” 操作设置。
- 主机的权重值越大,优先级越小,因子 越大,分数 所占的权重比例越大,如果权重模块的 分数大于 0 则会相应的拉低主机的优先级。
- 最大权重分数,来自系统参数 MaxSchedulerWeight 的值,默认值为 1000。
公用的权重模块
策略 None、Power_Saving、Evenly_Distributed、Vm_Evenly_Distributed,共同使用的权重模块有以下几种:
HA 权重模块的分数算法
new HostedEngineHAClusterWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
boolean isHostedEngine = vm.isHostedEngine();
if (isHostedEngine) {
// If the max HA score is higher than the max weight, then we normalize. Otherwise the ratio is 1, keeping the value as is
float ratio = MAXIMUM_HA_SCORE > MaxSchedulerWeight ? ((float) MaxSchedulerWeight / MAXIMUM_HA_SCORE) : 1;
for (VDS host : hosts) {
scores.add(new Pair<Guid, Integer>(host.getId(), MaxSchedulerWeight - Math.round(host.getHighlyAvailableScore() * ratio)));
}
} else {
fillDefaultScores(hosts, scores);
}
return scores;
}
- 最大的 HA 得分,系统默认为 2400。
- 如果运行的虚拟机是一个 HostedEngine,主机分数:MaxSchedulerWeight - Math.round(host.getHighlyAvailableScore() * ratio)。
- 比率(MAXIMUM_HA_SCORE > MaxSchedulerWeight ? ((float) MaxSchedulerWeight / MAXIMUM_HA_SCORE) : 1)。
- 虚拟机是 HostedEngine,优先选择高可用分数最高的主机;否则,所有主机优先级一致。
VmAffinityGroups 权重模块的分数算法
new VmAffinityWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
// reuse filter functionality with soft constraint
List<VDS> acceptableHostsList =
VmAffinityFilterPolicyUnit.getAcceptableHosts(false,
hosts,
vm,
new ArrayList<String>());
Map<Guid, VDS> acceptableHostsMap = new HashMap<Guid, VDS>();
if (acceptableHostsList != null) {
for (VDS acceptableHost : acceptableHostsList) {
acceptableHostsMap.put(acceptableHost.getId(), acceptableHost);
}
}
List<Pair<Guid, Integer>> retList = new ArrayList<Pair<Guid, Integer>>();
int score;
for (VDS host : hosts) {
score = 1;
if (!acceptableHostsMap.containsKey(host.getId())) {
score = MaxSchedulerWeight;
}
retList.add(new Pair<Guid, Integer>(host.getId(), score));
}
return retList;
}
- 定义 非强制性 关系组并且这个关系组设置组内的虚拟机必须 运行在一个主机上(Positive 类型)。
- 获取组内 运行状态 的虚拟机所在的主机,并且要求这个主机中的所有虚拟机都不能属于 Negative 类型的其他关系组。
- 定义满足以上条件的主机为可接受的。
- 进行权重分数计算的主机如果不属于可接受的主机,则分数为 最大权重分数,否则分数为 1。
- 关系组为空,则所有主机分数为 1。
- 没有关系组的主机或者属于可接受的主机,则分数为 1,否则为 最大权重分数。
OptimalForHaReservation 权重模块的分数算法
new HaReservationWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
log.info("Started HA reservation scoring method");
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
Map<Guid, Integer> hostsHaVmCount = new HashMap<Guid, Integer>();
// If the vm is not HA or the cluster is not marked as HA Reservation set default score.
VDSGroup vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
if (!vm.isAutoStartup() || !vdsGroup.supportsHaReservation()) {
fillDefaultScores(hosts, scores);
} else {
// Use a single call to the DB to retrieve all VM in the Cluster and map them by Host id
Map<Guid, List<VM>> hostId2HaVmMapping = HaReservationHandling.mapHaVmToHostByCluster(vdsGroup.getId());
int maxCount = 0;
for (VDS host : hosts) {
int count = 0;
if (hostId2HaVmMapping.containsKey(host.getId())) {
count = hostId2HaVmMapping.get(host.getId()).size();
}
maxCount = (maxCount < count) ? count : maxCount;
hostsHaVmCount.put(host.getId(), count);
}
// Fit count to scale of 0 to RATIO_FACTOR
if (maxCount > 0) {
for (VDS host : hosts) {
int fittedCount =
Math.round(hostsHaVmCount.get(host.getId()).floatValue() / maxCount * RATIO_FACTOR);
hostsHaVmCount.put(host.getId(), fittedCount);
}
}
// Get scale down param
Integer scaleDownParameter = 1;
if (parameters.get("ScaleDown") != null) {
scaleDownParameter = Integer.parseInt(parameters.get("ScaleDown"));
} else {
scaleDownParameter = Config.<Integer> getValue(ConfigValues.ScaleDownForHaReservation);
}
// Set the score pairs
for (VDS host : hosts) {
// Scale down if needed
int haCount = hostsHaVmCount.get(host.getId());
haCount = (int) Math.ceil(haCount / scaleDownParameter.floatValue());
scores.add(new Pair<Guid, Integer>(host.getId(), haCount));
log.infoFormat("Score for host:{0} is {1}", host.getName(), haCount);
}
}
return scores;
}
- 启用 HA Reservation 是管理器对群集中可以提供给 **高可用虚拟机 ** 的资源进行监控。管理器需要保证:当那些高可用虚拟机所在的主机出现问题时,群集可以提供足够的资源来把那些高可用虚拟机迁移到其它主机上。
- 如果主机所在群集没有设置启用 HA Reservation 或者启动的虚拟机没有设置 高度可用,那么主机权重分数为:0。
- 相对反计算出各主机包含的 高度可用 虚拟机数量。
- 根据虚拟机数量,计算出各主机对应的 hostsHaVmCount。
int maxCount = 0;
for (VDS host : hosts) {
int count = 0;
if (hostId2HaVmMapping.containsKey(host.getId())) {
count = hostId2HaVmMapping.get(host.getId()).size();
}
maxCount = (maxCount < count) ? count : maxCount;
hostsHaVmCount.put(host.getId(), count);
}
// Fit count to scale of 0 to RATIO_FACTOR
if (maxCount > 0) {
for (VDS host : hosts) {
int fittedCount =
Math.round(hostsHaVmCount.get(host.getId()).floatValue() / maxCount * RATIO_FACTOR);
hostsHaVmCount.put(host.getId(), fittedCount);
}
}
- 当前主机上的高可用虚拟机数 ÷ 所有主机中虚拟机最大数 × RATIO_FACTOR(默认值 100)。
- 如果没有在界面群集策略的属性值中设置 scaleDown 参数,就设置为系统属性 ScaleDownForHaReservation 的值,默认为 1。
- 根据 scaleDown 参数和 hostsHaVmCount,计算出最终的权重分数:Math.ceil(haCount / scaleDownParameter.floatValue())
- 虚拟机如果 高可用,并且群集支持 HaReservation,则优先选择虚拟机运行少的主机。
不同的权重模块
OptimalForEvenDistribution 权重模块的分数算法(主要应用于 Evenly_Distributed 群集策略)
new EvenDistributionWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
VDSGroup vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
boolean countThreadsAsCores = vdsGroup != null ? vdsGroup.getCountThreadsAsCores() : false;
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
scores.add(new Pair<Guid, Integer>(vds.getId(), calcEvenDistributionScore(vds, vm, countThreadsAsCores)));
}
return scores;
}
return (hostCpu / vcpu) + (pendingVcpus + vm.getNumOfCpus() + spmCpu) / hostCores;
- 权重分数等于 (主机的 CPU 使用百分比 ÷ 虚拟 CPU 消耗百分比) + (主机预计使用的虚拟 CPU 总数 + 虚拟机 CPU 数量 + SPM 消耗 CPU 数量) / 主机实际生效的 CPU 数量
- 如果设置了 将线程用作内核,那么主机实际生效的 CPU 数量等于 CPU 线程数量,否则等于 CPU 核数。
public static Integer getEffectiveCpuCores(VDS vds, boolean countThreadsAsCores) {
if (vds.getCpuThreads() != null
&& countThreadsAsCores) {
return vds.getCpuThreads();
} else {
return vds.getCpuCores();
}
}
- CPU 占用少的、非 SPM 的主机优先级高。
None 权重模块的分数算法(主要应用于 None 群集策略)
new NoneWeightPolicyUnit(policyUnit);
@Override
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
return super.score(hosts, vm, parameters);
}
- 沿用了 OptimalForEvenDistribution 权重模块的计算方法。
- CPU 占用少的、非 SPM 的主机优先级高。
OptimalForPowerSaving 权重模块的分数算法(主要应用于 Power_Saving 群集策略)
new PowerSavingWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
VDSGroup vdsGroup = null;
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
int score = MaxSchedulerWeight - 1;
if (vds.getVmCount() > 0) {
if (vdsGroup == null) {
vdsGroup = DbFacade.getInstance().getVdsGroupDao().get(hosts.get(0).getVdsGroupId());
}
score -=
calcEvenDistributionScore(vds, vm, vdsGroup != null ? vdsGroup.getCountThreadsAsCores() : false);
}
scores.add(new Pair<Guid, Integer>(vds.getId(), score));
}
return scores;
}
- 分数(最大权重分数 - 1 - Evenly_Distributed 方法计算出的分数)
- 与 Evenly_Distributed 算法相反,虚拟机会运行得更加集中,并且会优先选择 SPM。
OptimalForEvenGuestDistribution 权重模块的分数算法(主要应用于 VM_Evenly_Distributed 群集策略)
new EvenGuestDistributionWeightPolicyUnit(policyUnit);
public List<Pair<Guid, Integer>> score(List<VDS> hosts, VM vm, Map<String, String> parameters) {
List<Pair<Guid, Integer>> scores = new ArrayList<Pair<Guid, Integer>>();
for (VDS vds : hosts) {
scores.add(new Pair<Guid, Integer>(vds.getId(), calcEvenGuestDistributionScore(vds, parameters)));
}
return scores;
}
private int getOccupiedVmSlots(VDS vds, Map<String, String> parameters) {
int occupiedSlots = vds.getVmActive();
final int SPMVMCountGrace = NumberUtils.toInt(parameters.get("SpmVmGrace"),
spmVmGrace);
if (vds.isSpm())
occupiedSlots += SPMVMCountGrace;
return occupiedSlots;
}
private int calcEvenGuestDistributionScore(VDS vds, Map<String, String> parameters) {
return Math.max(0, getOccupiedVmSlots(vds, parameters));
}
- 作为 SPM 主机,比其他主机运行的虚拟机少多少,来自系统参数 SpmVmGraceForEvenGuestDistribute,默认值为 5。
- 非 SPM 主机,分数为主机上激活虚拟机数量总和。SPM 主机,分数(激活虚拟机数量总和 + 预留的用于分配的虚拟机数量)。
- 非 SPM 优先 SPM 主机,虚拟机运行少 的主机优先 虚拟机运行多 的主机。**
负载平衡器
None 负载平衡器
new NoneBalancePolicyUnit(policyUnit);
@Override
public Pair<List<Guid>, Guid> balance(VDSGroup cluster,
List<VDS> hosts,
Map<String, String> parameters,
ArrayList<String> messages) {
return null;
}
- 新的虚拟机会在群集中的一个,把策略值设置为 None 将不允许在主机间进行 负载 和电源共享。这是系统的默认值。
- None 策略的 balance 没有定义具体内容,所以虚拟机在启动后会一直在一个主机上。
OptimalForPowerSaving 负载平衡器
只在一部分主机中分配 CPU 处理负载,这可以为其它主机节省能源消耗。如果主机上的 CPU 负载处于低使用率状态,并且处于这个状态的时间超过了预先定义的时间,这个主机上的虚拟机将被迁移到其它主机上,并在迁移后关闭这个主机。如果一个主机的利用率已经达到了设置的最高值,新加入到这个主机的虚拟机将不会被启动。
参数 | 说明 |
---|---|
CpuOverCommitDurationMinutes | 在群集策略起作用前,一个主机可以在 CPU 负载超过利用率中所设置的值的情况下运行的 最长 时间(以分钟为单位)。通过这个设置,可以避免因为暂时的高 CPU 负载所带来的不必要的虚拟机迁移操作,默认获取系统参数 CpuOverCommitDurationMinutes 的值,默认值是 2 分钟。 |
HighUtilization | 最高利用率,一个百分比值,默认获取系统参数 LowUtilizationForPowerSave 的值,默认值为 10。 |
LowUtilization | 最低利用率,一个百分比值,默认获取系统参数 HighUtilizationForPowerSave 的值,默认值为 6。 |
return new PowerSavingBalancePolicyUnit(policyUnit);
public Pair<List<Guid>, Guid> balance(VDSGroup cluster,
List<VDS> hosts,
Map<String, String> parameters,
ArrayList<String> messages) {
final Pair<List<Guid>, Guid> migrationRule = super.balance(cluster, hosts, parameters, messages);
List<VDS> allHosts = DbFacade.getInstance().getVdsDao().getAllForVdsGroup(cluster.getId());
List<VDS> emptyHosts = new ArrayList<>();
List<VDS> maintenanceHosts = new ArrayList<>();
List<VDS> downHosts = new ArrayList<>();
getHostLists(allHosts, parameters, emptyHosts, maintenanceHosts, downHosts);
Pair<VDS, VDSStatus> action = evaluatePowerManagementSituation(
cluster,
downHosts,
maintenanceHosts,
emptyHosts,
parameters);
if (action != null) {
processPmAction(action);
}
return migrationRule;
}
- 系统参数 HostsInReserve 主机储备必须配置为大于 0,才能通过电源管理自动启动主机。
- 系统参数 EnableAutomaticHostPowerManagement 必须设置为 true,才能进行自动电源管理,非 SPM 主机会自动切换至维护状态,然后关机。
- 系统参数 UtilizationThresholdInPercent 利用率的门槛值,默认值为 80。
- 系统参数 VcpuConsumptionPercentage,虚拟 CPU 消耗百分比,默认值为 10。
- 主机的 CPU 利用率 超过了 highVdsCount 并达到了 设定的时间(CpuOverCommitDurationMinutes),引擎对该主机上的虚拟机进行迁移,将虚拟机迁移到 CPU 利用率最低 的主机上,该动作重复执行,直到主机的 CPU 利用率 小于 highVdsCount。
- highVdsCount(Math.min(Config.<Integer> getValue(ConfigValues.UtilizationThresholdInPercent) * highUtilization / 100, highUtilization - Config.<Integer> getValue(ConfigValues.VcpuConsumptionPercentage)))。取(利用率的临界值 × 最高利用率 ÷ 100)和(最高利用率 - 虚拟 CPU 消耗百分比)的更小值。
- 当主机的 CPU 利用率 低于了设定的 最低利用率(LowUtilization) 并达到了 设定的时间,引擎会在满足 最高利用率 条件的情况下将虚拟机迁移到其他主机上,虚拟机全部迁移后,引擎会关闭该主机。
- 群集中所有主机 CPU 利用率 都低于 最低利用率 的时候,不会进行迁移。
OptimalForEvenDistribution 负载平衡器
new EvenDistributionBalancePolicyUnit(policyUnit);
- 新的虚拟机会运行在 CPU利用率 最低的主机上。
- 主机的 CPU 利用率 超过了 highVdsCount 并达到了 设定的时间(CpuOverCommitDurationMinutes),引擎对该主机上的虚拟机进行迁移,将虚拟机迁移到 CPU 利用率最低 的主机上,该动作重复执行,直到主机的 CPU 利用率 小于 highVdsCount。
- highVdsCount(Math.min(Config.<Integer> getValue(ConfigValues.UtilizationThresholdInPercent) * highUtilization / 100, highUtilization - Config.<Integer> getValue(ConfigValues.VcpuConsumptionPercentage)))。取(利用率的临界值 × 最高利用率 ÷ 100)和(最高利用率 - 虚拟 CPU 消耗百分比)的更小值。
- 当主机的 CPU 利用率 低于了设定的 最低利用率(LowUtilization) 并达到了 设定的时间,引擎会在满足 最高利用率 条件的情况下将虚拟机迁移到其他主机上,虚拟机全部迁移后,引擎会关闭该主机。
OptimalForEvenGuestDistribution 负载平衡器
new EvenGuestDistributionBalancePolicyUnit(policyUnit);
参数 | 说明 |
---|---|
SpmVmGrace | SPM 该变量定义了 SPM 主机究竟比其他主机运行的虚拟机少多少,默认获取系统参数 SpmVmGraceForEvenGuestDistribute 的值,默认值为 5。 |
MigrationThreshold | 在虚拟机从主机迁移之前,定义一个缓冲区。它最大限度的包容了最高利用率主机和最低利用率主机在虚拟机数量上的不同。当在群集中的每台主机都有一个虚拟机计数在值内时,该群集是均衡的,默认系统参数 MigrationThresholdForEvenGuestDistribute 的值,默认值为:5。 |
HighVmCount | 设置可在每台服务器运行虚拟机的最大数目。超过此限制限定服务器重载,默认系统参数 HighVmCountForEvenGuestDistribute 的值,默认值为:10 |
- 当某个主机上运行的虚拟机数量超过 过载值(HighVmCount),并且 最高利用率 主机上的虚拟机数量和 最低利用率 主机上的虚拟机数量的差值大于 容忍度值(MigrationThreshold),引擎会将该主机上的虚拟机迁移到最低利用率的主机上。