Skip to content

Commit 10cd150

Browse files
committed
CPU to Memory weight based algorithm to order cluster
host.capacityType.to.order.clusters config will support new algorithm: COMBINED which will work with host.capacityType.to.order.clusters.cputomemoryweight and capacity will be computed based on CPU and memory both and using weight factor
1 parent 41b4f0a commit 10cd150

File tree

11 files changed

+231
-34
lines changed

11 files changed

+231
-34
lines changed

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,11 @@ public class ApiConstants {
9090
public static final String CONVERT_INSTANCE_HOST_ID = "convertinstancehostid";
9191
public static final String CONVERT_INSTANCE_STORAGE_POOL_ID = "convertinstancepoolid";
9292
public static final String ENABLED_REVOCATION_CHECK = "enabledrevocationcheck";
93+
public static final String COMBINED_CAPACITY_ORDERING = "COMBINED";
9394
public static final String CONTROLLER = "controller";
9495
public static final String CONTROLLER_UNIT = "controllerunit";
9596
public static final String COPY_IMAGE_TAGS = "copyimagetags";
97+
public static final String CPU_OVERCOMMIT_RATIO = "cpuOvercommitRatio";
9698
public static final String CSR = "csr";
9799
public static final String PRIVATE_KEY = "privatekey";
98100
public static final String DATASTORE_HOST = "datastorehost";
@@ -120,6 +122,7 @@ public class ApiConstants {
120122
public static final String COMMAND = "command";
121123
public static final String CMD_EVENT_TYPE = "cmdeventtype";
122124
public static final String COMPONENT = "component";
125+
public static final String CPU = "CPU";
123126
public static final String CPU_CORE_PER_SOCKET = "cpucorepersocket";
124127
public static final String CPU_NUMBER = "cpunumber";
125128
public static final String CPU_SPEED = "cpuspeed";
@@ -337,6 +340,7 @@ public class ApiConstants {
337340
public static final String MAX_BACKUPS = "maxbackups";
338341
public static final String MAX_CPU_NUMBER = "maxcpunumber";
339342
public static final String MAX_MEMORY = "maxmemory";
343+
public static final String MEMORY_OVERCOMMIT_RATIO = "memoryOvercommitRatio";
340344
public static final String MIN_CPU_NUMBER = "mincpunumber";
341345
public static final String MIN_MEMORY = "minmemory";
342346
public static final String MIGRATION_TYPE = "migrationtype";
@@ -432,6 +436,7 @@ public class ApiConstants {
432436
public static final String PUBLIC_END_PORT = "publicendport";
433437
public static final String PUBLIC_ZONE = "publiczone";
434438
public static final String PURGE_RESOURCES = "purgeresources";
439+
public static final String RAM = "RAM";
435440
public static final String RECEIVED_BYTES = "receivedbytes";
436441
public static final String RECONNECT = "reconnect";
437442
public static final String RECOVER = "recover";

engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ public interface ConfigurationManager {
6565
"allow.non.rfc1918.compliant.ips", "Advanced", "false",
6666
"Allows non-compliant RFC 1918 IPs for Shared, Isolated networks and VPCs", true, null);
6767

68+
ConfigKey<Float> HostCapacityTypeCpuMemoryWeight = new ConfigKey<Float>(ConfigKey.CATEGORY_ADVANCED, Float.class, "host.capacityType.to.order.clusters.cputomemoryweight",
69+
"0.5",
70+
"CPU to Memory weight used for COMBINED capacityTye to order cluster and host",
71+
true, ConfigKey.Scope.Global);
72+
6873
/**
6974
* @param offering
7075
* @return

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
3030

3131
List<CapacityVO> listByHostIdTypes(Long hostId, List<Short> capacityTypes);
3232

33-
List<Long> listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone);
33+
List<Long> listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, boolean isZone);
3434

3535
List<Long> listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType);
3636

@@ -48,7 +48,7 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
4848

4949
List<SummedCapacity> findFilteredCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, List<Long> hostIds, List<Long> poolIds);
5050

51-
List<Long> listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType);
51+
List<Long> listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam);
5252

5353
Pair<List<Long>, Map<Long, Double>> orderPodsByAggregateCapacity(long zoneId, short capacityType);
5454

@@ -65,4 +65,10 @@ List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, L
6565
float findClusterConsumption(Long clusterId, short capacityType, long computeRequested);
6666

6767
Pair<List<Long>, Map<Long, Double>> orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityType);
68+
69+
List<CapacityVO> listHostCapacityByCapacityTypes(Long zoneId, Long clusterId, List<Short> capacityTypes);
70+
71+
List<CapacityVO> listPodCapacityByCapacityTypes(Long zoneId, List<Short> capacityTypes);
72+
73+
List<CapacityVO> listClusterCapacityByCapacityTypes(Long zoneId, Long podId, long vmId, List<Short> capacityTypes);
6874
}

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ public List<CapacityVO> listByHostIdTypes(Long hostId, List<Short> capacityTypes
684684
}
685685

686686
@Override
687-
public List<Long> listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone) {
687+
public List<Long> listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, boolean isZone) {
688688
TransactionLegacy txn = TransactionLegacy.currentTxn();
689689
PreparedStatement pstmt = null;
690690
List<Long> result = new ArrayList<Long>();
@@ -1068,7 +1068,59 @@ public Pair<List<Long>, Map<Long, Double>> orderHostsByFreeCapacity(Long zoneId,
10681068
}
10691069

10701070
@Override
1071-
public List<Long> listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType) {
1071+
public List<CapacityVO> listHostCapacityByCapacityTypes(Long zoneId, Long clusterId, List<Short> capacityTypes) {
1072+
SearchBuilder<CapacityVO> sb = createSearchBuilder();
1073+
sb.and("zoneId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
1074+
sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ);
1075+
sb.and("capacityTypes", sb.entity().getCapacityType(), SearchCriteria.Op.IN);
1076+
sb.done();
1077+
1078+
SearchCriteria<CapacityVO> sc = sb.create();
1079+
if (zoneId != null) {
1080+
sc.setParameters("zoneId", zoneId);
1081+
}
1082+
if (clusterId != null) {
1083+
sc.setParameters("clusterId", clusterId);
1084+
}
1085+
sc.setParameters("capacityTypes", capacityTypes.toArray());
1086+
return listBy(sc);
1087+
}
1088+
1089+
@Override
1090+
public List<CapacityVO> listPodCapacityByCapacityTypes(Long zoneId, List<Short> capacityTypes) {
1091+
SearchBuilder<CapacityVO> sb = createSearchBuilder();
1092+
sb.and("zoneId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
1093+
sb.and("capacityTypes", sb.entity().getCapacityType(), SearchCriteria.Op.IN);
1094+
sb.done();
1095+
SearchCriteria<CapacityVO> sc = sb.create();
1096+
if (zoneId != null) {
1097+
sc.setParameters("zoneId", zoneId);
1098+
}
1099+
sc.setParameters("capacityTypes", capacityTypes.toArray());
1100+
return listBy(sc);
1101+
}
1102+
1103+
@Override
1104+
public List<CapacityVO> listClusterCapacityByCapacityTypes(Long zoneId, Long podId, long vmId, List<Short> capacityTypes) {
1105+
SearchBuilder<CapacityVO> sb = createSearchBuilder();
1106+
sb.and("zoneId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
1107+
sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ);
1108+
sb.and("capacityTypes", sb.entity().getCapacityType(), SearchCriteria.Op.IN);
1109+
sb.done();
1110+
1111+
SearchCriteria<CapacityVO> sc = sb.create();
1112+
if (zoneId != null) {
1113+
sc.setParameters("zoneId", zoneId);
1114+
}
1115+
if (podId != null) {
1116+
sc.setParameters("podId", podId);
1117+
}
1118+
sc.setParameters("capacityTypes", capacityTypes.toArray());
1119+
return listBy(sc);
1120+
}
1121+
1122+
@Override
1123+
public List<Long> listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam) {
10721124
TransactionLegacy txn = TransactionLegacy.currentTxn();
10731125
PreparedStatement pstmt = null;
10741126
List<Long> result = new ArrayList<Long>();

engine/schema/src/test/java/com/cloud/capacity/dao/CapacityDaoImplTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,11 @@ public void testListClustersInZoneOrPodByHostCapacitiesEmpty() throws Exception
205205
when(pstmt.executeQuery()).thenReturn(resultSet);
206206
when(resultSet.next()).thenReturn(false);
207207

208-
List<Long> resultZone = capacityDao.listClustersInZoneOrPodByHostCapacities(1L, 123L, 2, 2048L, (short)0, true);
208+
List<Long> resultZone = capacityDao.listClustersInZoneOrPodByHostCapacities(1L, 123L, 2, 2048L, true);
209209
assertNotNull(resultZone);
210210
assertTrue(resultZone.isEmpty());
211211

212-
List<Long> resultPod = capacityDao.listClustersInZoneOrPodByHostCapacities(1L, 123L, 2, 2048L, (short)0, false);
212+
List<Long> resultPod = capacityDao.listClustersInZoneOrPodByHostCapacities(1L, 123L, 2, 2048L, false);
213213
assertNotNull(resultPod);
214214
assertTrue(resultPod.isEmpty());
215215
}
@@ -281,7 +281,7 @@ public void testListPodsByHostCapacitiesEmptyResult() throws Exception {
281281
when(pstmt.executeQuery()).thenReturn(resultSet);
282282
when(resultSet.next()).thenReturn(false);
283283

284-
List<Long> result = capacityDao.listPodsByHostCapacities(1L, 2, 1024L, (short)0);
284+
List<Long> result = capacityDao.listPodsByHostCapacities(1L, 2, 1024L);
285285
assertNotNull(result);
286286
assertTrue(result.isEmpty());
287287
}

plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe
359359
clustersWithEnoughCapacity.add(3L);
360360
when(
361361
capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, 12L, noOfCpusInOffering * cpuSpeedInOffering, ramInOffering * 1024L * 1024L,
362-
Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersWithEnoughCapacity);
362+
true)).thenReturn(clustersWithEnoughCapacity);
363363

364364
Map<Long, Double> clusterCapacityMap = new HashMap<Long, Double>();
365365
clusterCapacityMap.put(1L, 2048D);

server/src/main/java/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
import javax.naming.ConfigurationException;
3131

3232
import com.cloud.agent.manager.allocator.HostAllocator;
33+
import com.cloud.capacity.Capacity;
3334
import com.cloud.capacity.CapacityManager;
3435
import com.cloud.capacity.CapacityVO;
3536
import com.cloud.capacity.dao.CapacityDao;
3637
import com.cloud.configuration.Config;
38+
import com.cloud.configuration.ConfigurationManager;
3739
import com.cloud.dc.ClusterDetailsDao;
3840
import com.cloud.dc.dao.ClusterDao;
3941
import com.cloud.deploy.DeploymentPlan;
@@ -64,9 +66,11 @@
6466
import com.cloud.vm.dao.UserVmDetailsDao;
6567
import com.cloud.vm.dao.VMInstanceDao;
6668

69+
import org.apache.cloudstack.api.ApiConstants;
6770
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
6871
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
6972

73+
import org.jetbrains.annotations.NotNull;
7074
import org.springframework.stereotype.Component;
7175

7276
/**
@@ -372,13 +376,7 @@ protected List<Host> allocateTo(DeploymentPlan plan, ServiceOffering offering, V
372376
private List<? extends Host> reorderHostsByCapacity(DeploymentPlan plan, List<? extends Host> hosts) {
373377
Long zoneId = plan.getDataCenterId();
374378
Long clusterId = plan.getClusterId();
375-
//Get capacity by which we should reorder
376-
String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key());
377-
short capacityType = CapacityVO.CAPACITY_TYPE_CPU;
378-
if("RAM".equalsIgnoreCase(capacityTypeToOrder)){
379-
capacityType = CapacityVO.CAPACITY_TYPE_MEMORY;
380-
}
381-
Pair<List<Long>, Map<Long, Double>> result = _capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType);
379+
Pair<List<Long>, Map<Long, Double>> result = getOrderedHostsByCapacity(zoneId, clusterId);
382380
List<Long> hostIdsByFreeCapacity = result.first();
383381
Map<Long, String> sortedHostByCapacity = result.second().entrySet()
384382
.stream()
@@ -407,6 +405,54 @@ private List<? extends Host> reorderHostsByCapacity(DeploymentPlan plan, List<?
407405
return reorderedHosts;
408406
}
409407

408+
private Pair<List<Long>, Map<Long, Double>> getOrderedHostsByCapacity(Long zoneId, Long clusterId) {
409+
double cpuToMemoryWeight = ConfigurationManager.HostCapacityTypeCpuMemoryWeight.value();
410+
// Get capacity by which we should reorder
411+
short capacityType = getCapacityType(cpuToMemoryWeight);
412+
if (capacityType >= 0) { // for CPU or RAM
413+
return _capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType);
414+
}
415+
List<CapacityVO> capacities = _capacityDao.listHostCapacityByCapacityTypes(zoneId, clusterId,
416+
List.of(Capacity.CAPACITY_TYPE_CPU, Capacity.CAPACITY_TYPE_MEMORY));
417+
Map<Long, Double> hostByComputedCapacity = getHostByCombinedCapacities(capacities, cpuToMemoryWeight);
418+
return new Pair<>(new ArrayList<>(hostByComputedCapacity.keySet()), hostByComputedCapacity);
419+
}
420+
421+
short getCapacityType(double cpuToMemoryWeight) {
422+
String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key());
423+
short capacityType = CapacityVO.CAPACITY_TYPE_CPU;
424+
if (ApiConstants.RAM.equalsIgnoreCase(capacityTypeToOrder)){
425+
capacityType = CapacityVO.CAPACITY_TYPE_MEMORY;
426+
} else if (ApiConstants.COMBINED_CAPACITY_ORDERING.equalsIgnoreCase(capacityTypeToOrder)) {
427+
capacityType = -1;
428+
}
429+
430+
if (cpuToMemoryWeight == 1) {
431+
capacityType = CapacityVO.CAPACITY_TYPE_CPU;
432+
}
433+
if (cpuToMemoryWeight == 0) {
434+
capacityType = CapacityVO.CAPACITY_TYPE_MEMORY;
435+
}
436+
return capacityType;
437+
}
438+
439+
440+
@NotNull
441+
private static Map<Long, Double> getHostByCombinedCapacities(List<CapacityVO> capacities, double cpuToMemoryWeight) {
442+
Map<Long, Double> hostByComputedCapacity = new HashMap<>();
443+
for (CapacityVO capacityVO : capacities) {
444+
long hostId = capacityVO.getHostOrPoolId();
445+
double applicableWeight = capacityVO.getCapacityType() == Capacity.CAPACITY_TYPE_CPU ? cpuToMemoryWeight : 1 - cpuToMemoryWeight;
446+
double capacityMetric = applicableWeight * (capacityVO.getTotalCapacity() - (capacityVO.getUsedCapacity() + capacityVO.getReservedCapacity()))/capacityVO.getTotalCapacity();
447+
hostByComputedCapacity.merge(hostId, capacityMetric, Double::sum);
448+
}
449+
450+
return hostByComputedCapacity.entrySet()
451+
.stream()
452+
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
453+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
454+
}
455+
410456
private List<? extends Host> reorderHostsByNumberOfVms(DeploymentPlan plan, List<? extends Host> hosts, Account account) {
411457
if (account == null) {
412458
return hosts;

server/src/main/java/com/cloud/configuration/Config.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,9 @@ public enum Config {
897897
String.class,
898898
"host.capacityType.to.order.clusters",
899899
"CPU",
900-
"The host capacity type (CPU or RAM) is used by deployment planner to order clusters during VM resource allocation",
901-
"CPU,RAM"),
900+
"The host capacity type (CPU, RAM, COMBINED) is used by deployment planner to order clusters during VM resource allocation",
901+
"CPU,RAM,COMBINED"),
902+
902903
ApplyAllocationAlgorithmToPods(
903904
"Advanced",
904905
ManagementServer.class,

server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8252,7 +8252,7 @@ public ConfigKey<?>[] getConfigKeys() {
82528252
BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE,
82538253
VM_SERVICE_OFFERING_MAX_CPU_CORES, VM_SERVICE_OFFERING_MAX_RAM_SIZE, MIGRATE_VM_ACROSS_CLUSTERS,
82548254
ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN,
8255-
ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, DELETE_QUERY_BATCH_SIZE, AllowNonRFC1918CompliantIPs
8255+
ALLOW_DOMAIN_ADMINS_TO_CREATE_TAGGED_OFFERINGS, DELETE_QUERY_BATCH_SIZE, AllowNonRFC1918CompliantIPs, HostCapacityTypeCpuMemoryWeight
82568256
};
82578257
}
82588258

0 commit comments

Comments
 (0)