mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-3664:
scaling up vms was not considering parameter cluster.(memory/cpu).allocated.capacity.disablethreshold. Fixed it Also added overprovisioning factor retrieval at the cluster level for host capacity check
This commit is contained in:
parent
4a9da03760
commit
e79350d256
|
|
@ -91,4 +91,15 @@ public interface CapacityManager {
|
|||
* @return true if the count of host's running VMs >= hypervisor limit
|
||||
*/
|
||||
boolean checkIfHostHasCpuCapability(long hostId, Integer cpuNum, Integer cpuSpeed);
|
||||
|
||||
/**
|
||||
* Check if cluster will cross threshold if the cpu/memory requested are accomodated
|
||||
* @param clusterId the clusterId to check
|
||||
* @param cpuRequested cpu requested
|
||||
* @param ramRequested cpu requested
|
||||
* @return true if the customer crosses threshold, false otherwise
|
||||
*/
|
||||
boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested);
|
||||
|
||||
float getClusterOverProvisioningFactor(Long clusterId, short capacityType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,11 +45,12 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
|
|||
|
||||
Pair<List<Long>, Map<Long, Double>> orderPodsByAggregateCapacity(long zoneId, short capacityType);
|
||||
|
||||
List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId, String resourceState);
|
||||
List<SummedCapacity> findCapacityBy(Integer capacityType, Long zoneId,
|
||||
Long podId, Long clusterId, String resourceState);
|
||||
List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);
|
||||
void updateCapacityState(Long dcId, Long podId, Long clusterId,
|
||||
Long hostId, String capacityState);
|
||||
List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested);
|
||||
|
||||
List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit);
|
||||
|
||||
void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState);
|
||||
|
||||
List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, String ConfigName, long computeRequested);
|
||||
float findClusterConsumption(Long clusterId, short capacityType, long computeRequested);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import java.util.Map;
|
|||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.dc.ClusterDetailsDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -161,19 +164,24 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
|
|||
* query from the configuration table
|
||||
*
|
||||
* */
|
||||
private static final String LIST_CLUSTERS_CROSSING_THRESHOLD =
|
||||
"SELECT clusterList.cluster_id "
|
||||
+ "FROM (SELECT cluster.cluster_id cluster_id, ( (sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, cluster.configValue value "
|
||||
+ "FROM (SELECT capacity.cluster_id cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, capacity.total_capacity * overcommit.value total, "
|
||||
+ "CASE (SELECT count(*) FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) "
|
||||
+ "WHEN 1 THEN (CASE WHEN (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ?) is NULL "
|
||||
+ "THEN (SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?)"
|
||||
+ "ELSE (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) END )"
|
||||
+ "ELSE ( SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " + "END configValue "
|
||||
+ "FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` overcommit ON overcommit.cluster_id = capacity.cluster_id "
|
||||
+ "WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 AND overcommit.name = ?) cluster " +
|
||||
|
||||
"GROUP BY cluster.cluster_id) clusterList " + "WHERE clusterList.ratio > clusterList.value; ";
|
||||
private static final String LIST_CLUSTERS_CROSSING_THRESHOLD = "SELECT clusterList.cluster_id " +
|
||||
"FROM ( SELECT cluster.cluster_id cluster_id, ( (sum(cluster.used) + sum(cluster.reserved) + ?)/sum(cluster.total) ) ratio, cluster.configValue value " +
|
||||
"FROM ( SELECT capacity.cluster_id cluster_id, capacity.used_capacity used, capacity.reserved_capacity reserved, capacity.total_capacity * overcommit.value total, " +
|
||||
"CASE (SELECT count(*) FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) " +
|
||||
"WHEN 1 THEN ( CASE WHEN (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ?) is NULL " +
|
||||
"THEN (SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?)" +
|
||||
"ELSE (SELECT details.value FROM `cloud`.`cluster_details` details WHERE details.cluster_id = capacity.cluster_id AND details.name = ? ) END )" +
|
||||
"ELSE ( SELECT config.value FROM `cloud`.`configuration` config WHERE config.name = ?) " +
|
||||
"END configValue " +
|
||||
"FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` overcommit ON overcommit.cluster_id = capacity.cluster_id " +
|
||||
"WHERE capacity.data_center_id = ? AND capacity.capacity_type = ? AND capacity.total_capacity > 0 AND overcommit.name = ?) cluster " +
|
||||
|
||||
"GROUP BY cluster.cluster_id) clusterList " +
|
||||
"WHERE clusterList.ratio > clusterList.value; ";
|
||||
|
||||
private static final String FIND_CLUSTER_CONSUMPTION_RATIO = "select ( (sum(capacity.used_capacity) + sum(capacity.reserved_capacity) + ?)/sum(capacity.total_capacity) ) " +
|
||||
"from op_host_capacity capacity where cluster_id = ? and capacity_type = ?;";
|
||||
|
||||
public CapacityDaoImpl() {
|
||||
_hostIdTypeSearch = createSearchBuilder();
|
||||
|
|
@ -883,4 +891,26 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
|
|||
s_logger.warn("Error updating CapacityVO", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float findClusterConsumption(Long clusterId, short capacityType, long computeRequested){
|
||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||
StringBuilder sql = new StringBuilder(FIND_CLUSTER_CONSUMPTION_RATIO);
|
||||
PreparedStatement pstmt = null;
|
||||
try {
|
||||
pstmt = txn.prepareAutoCloseStatement(sql.toString());
|
||||
|
||||
pstmt.setLong(1, computeRequested);
|
||||
pstmt.setLong(2, clusterId);
|
||||
pstmt.setShort(3, capacityType);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
return rs.getFloat(1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("Error checking cluster threshold", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@ import javax.ejb.Local;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.deploy.DeploymentClusterPlanner;
|
||||
import com.cloud.deploy.DeploymentPlanner;
|
||||
import com.cloud.event.UsageEventVO;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.framework.config.ConfigDepot;
|
||||
|
|
@ -94,6 +97,7 @@ import com.cloud.vm.dao.UserVmDao;
|
|||
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||
import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
|
||||
|
||||
@Local(value = CapacityManager.class)
|
||||
public class CapacityManagerImpl extends ManagerBase implements CapacityManager, StateListener<State, VirtualMachine.Event, VirtualMachine>, Listener, ResourceListener,
|
||||
|
|
@ -852,6 +856,50 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getClusterOverProvisioningFactor(Long clusterId, short capacityType){
|
||||
|
||||
String capacityOverProvisioningName = "";
|
||||
if(capacityType == Capacity.CAPACITY_TYPE_CPU){
|
||||
capacityOverProvisioningName = "cpuOvercommitRatio";
|
||||
}else if(capacityType == Capacity.CAPACITY_TYPE_MEMORY){
|
||||
capacityOverProvisioningName = "memoryOvercommitRatio";
|
||||
}else{
|
||||
throw new CloudRuntimeException("Invalid capacityType - " + capacityType);
|
||||
}
|
||||
|
||||
ClusterDetailsVO clusterDetailCpu = _clusterDetailsDao.findDetail(clusterId, capacityOverProvisioningName);
|
||||
Float clusterOverProvisioningRatio = Float.parseFloat(clusterDetailCpu.getValue());
|
||||
return clusterOverProvisioningRatio;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkIfClusterCrossesThreshold(Long clusterId, Integer cpuRequested, long ramRequested){
|
||||
|
||||
Float clusterCpuOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_CPU);
|
||||
Float clusterMemoryOverProvisioning = getClusterOverProvisioningFactor(clusterId, Capacity.CAPACITY_TYPE_MEMORY);
|
||||
Float clusterCpuCapacityDisableThreshold = DeploymentClusterPlanner.ClusterCPUCapacityDisableThreshold.valueIn(clusterId);
|
||||
Float clusterMemoryCapacityDisableThreshold = DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.valueIn(clusterId);
|
||||
|
||||
float cpuConsumption = _capacityDao.findClusterConsumption(clusterId, Capacity.CAPACITY_TYPE_CPU, cpuRequested);
|
||||
if(cpuConsumption/clusterCpuOverProvisioning > clusterCpuCapacityDisableThreshold){
|
||||
s_logger.debug("Cluster: " +clusterId + " cpu consumption " + cpuConsumption/clusterCpuOverProvisioning
|
||||
+ " crosses disable threshold " + clusterCpuCapacityDisableThreshold);
|
||||
return true;
|
||||
}
|
||||
|
||||
float memoryConsumption = _capacityDao.findClusterConsumption(clusterId, Capacity.CAPACITY_TYPE_MEMORY, ramRequested);
|
||||
if(memoryConsumption/clusterMemoryOverProvisioning > clusterMemoryCapacityDisableThreshold){
|
||||
s_logger.debug("Cluster: " +clusterId + " memory consumption " + memoryConsumption/clusterMemoryOverProvisioning
|
||||
+ " crosses disable threshold " + clusterMemoryCapacityDisableThreshold);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
|
||||
// TODO Auto-generated method stub
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import javax.naming.ConfigurationException;
|
|||
|
||||
import com.cloud.event.UsageEventVO;
|
||||
import com.cloud.uuididentity.UUIDManager;
|
||||
import com.cloud.capacity.Capacity;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -1306,6 +1308,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
int currentCpu = currentServiceOffering.getCpu();
|
||||
int currentMemory = currentServiceOffering.getRamSize();
|
||||
int currentSpeed = currentServiceOffering.getSpeed();
|
||||
int memoryDiff = newMemory - currentMemory;
|
||||
int cpuDiff = newCpu*newSpeed - currentCpu*currentSpeed;
|
||||
|
||||
// Don't allow to scale when (Any of the new values less than current values) OR (All current and new values are same)
|
||||
if ((newSpeed < currentSpeed || newMemory < currentMemory || newCpu < currentCpu) ||
|
||||
|
|
@ -1328,14 +1332,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
if (vmInstance.getState().equals(State.Running)) {
|
||||
int retry = _scaleRetry;
|
||||
ExcludeList excludes = new ExcludeList();
|
||||
|
||||
// Check zone wide flag
|
||||
boolean enableDynamicallyScaleVm = EnableDynamicallyScaleVm.valueIn(vmInstance.getDataCenterId());
|
||||
if (!enableDynamicallyScaleVm) {
|
||||
throw new PermissionDeniedException("Dynamically scaling virtual machines is disabled for this zone, please contact your admin");
|
||||
}
|
||||
|
||||
// Check vm flag
|
||||
if (!vmInstance.isDynamicallyScalable()) {
|
||||
throw new CloudRuntimeException("Unable to Scale the vm: " + vmInstance.getUuid() + " as vm does not have tools to support dynamic scaling");
|
||||
}
|
||||
|
||||
// Check disable threshold for cluster is not crossed
|
||||
HostVO host = _hostDao.findById(vmInstance.getHostId());
|
||||
if(_capacityMgr.checkIfClusterCrossesThreshold(host.getClusterId(), cpuDiff, memoryDiff)){
|
||||
throw new CloudRuntimeException("Unable to scale vm: " + vmInstance.getUuid() + " due to insufficient resources");
|
||||
}
|
||||
|
||||
while (retry-- != 0) { // It's != so that it can match -1.
|
||||
try {
|
||||
boolean existingHostHasCapacity = false;
|
||||
|
|
@ -1344,15 +1358,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
if (newCpu > currentCpu) {
|
||||
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long(newCpu - currentCpu));
|
||||
}
|
||||
if (newMemory > currentMemory) {
|
||||
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long(newMemory - currentMemory));
|
||||
|
||||
if (memoryDiff > 0) {
|
||||
_resourceLimitMgr.incrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (memoryDiff));
|
||||
}
|
||||
|
||||
// #1 Check existing host has capacity
|
||||
if( !excludes.shouldAvoid(ApiDBUtils.findHostById(vmInstance.getHostId())) ){
|
||||
existingHostHasCapacity = _capacityMgr.checkIfHostHasCpuCapability(vmInstance.getHostId(), newCpu, newSpeed)
|
||||
&& _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), newServiceOffering.getSpeed() - currentServiceOffering.getSpeed(),
|
||||
(newServiceOffering.getRamSize() - currentServiceOffering.getRamSize()) * 1024L * 1024L, false, ApiDBUtils.getCpuOverprovisioningFactor(), 1f, false); // TO DO fill it with mem.
|
||||
&& _capacityMgr.checkIfHostHasCapacity(vmInstance.getHostId(), cpuDiff,
|
||||
(memoryDiff) * 1024L * 1024L, false, _capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_CPU),
|
||||
_capacityMgr.getClusterOverProvisioningFactor(host.getClusterId(), Capacity.CAPACITY_TYPE_MEMORY), false);
|
||||
excludes.addHost(vmInstance.getHostId());
|
||||
}
|
||||
|
||||
|
|
@ -1392,8 +1408,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
if (newCpu > currentCpu) {
|
||||
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.cpu, new Long(newCpu - currentCpu));
|
||||
}
|
||||
if (newMemory > currentMemory) {
|
||||
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long(newMemory - currentMemory));
|
||||
|
||||
if (memoryDiff > 0) {
|
||||
_resourceLimitMgr.decrementResourceCount(caller.getAccountId(), ResourceType.memory, new Long (memoryDiff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue