Bug 11617: Ensure the Deployment planner is choosing clusters based on aggregate capacity

Changes:
- We were ordering clusters based on capacity of the first-fit host found in each cluster. Due to this, there were cases where we deployed VMs to one cluster instead of balancing off within clusters.
- Now we order the list of clusters by aggregate capacity and choose the ones that have enough capacity for the required VM in this order.
- This should balance the load between clusters instead of bombarding one.

Conflicts:

	server/src/com/cloud/capacity/dao/CapacityDao.java
	server/src/com/cloud/capacity/dao/CapacityDaoImpl.java
This commit is contained in:
prachi 2011-10-03 15:37:38 -07:00
parent eacb9dde26
commit e0a179752d
3 changed files with 75 additions and 39 deletions

View File

@ -21,16 +21,16 @@ package com.cloud.capacity.dao;
import java.util.List;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
import com.cloud.utils.db.GenericDao;
public interface CapacityDao extends GenericDao<CapacityVO, Long> {
CapacityVO findByHostIdType(Long hostId, short capacityType);
List<Long> orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor);
List<Long> listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor);
List<Long> listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType, float cpuOverprovisioningFactor);
List<SummedCapacity> findCapacityByType(short capacityType, Long zoneId, Long podId,
Long clusterId, Long startIndex, Long pageSize);
boolean removeBy(Short capacityType, Long zoneId, Long podId, Long clusterId);
List<SummedCapacity> findByClusterPodZone(Long zoneId, Long podId, Long clusterId);
List<SummedCapacity> findNonSharedStorageForClusterPodZone(Long zoneId,Long podId, Long clusterId);
List<Long> orderClustersByAggregateCapacity(long id, short capacityType, boolean isZone, float cpuOverprovisioningFactor);
}

View File

@ -30,20 +30,16 @@ import org.apache.log4j.Logger;
import com.cloud.capacity.Capacity;
import com.cloud.capacity.CapacityVO;
import com.cloud.host.dao.HostDaoImpl;
import com.cloud.storage.Storage;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.StoragePoolDaoImpl;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
@ -59,18 +55,22 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART1 = "SELECT DISTINCT capacity.cluster_id FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster` cluster on (cluster.id = capacity.cluster_id AND cluster.removed is NULL) WHERE ";
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART2 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ? " +
"AND cluster_id IN (SELECT distinct cluster_id FROM `cloud`.`op_host_capacity` WHERE ";
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) " +
"ORDER BY ((total_capacity * ?) - used_capacity + reserved_capacity) DESC";
private static final String LIST_CLUSTERSINZONE_BY_HOST_CAPACITIES_PART3 = " AND capacity_type = ? AND ((total_capacity * ?) - used_capacity + reserved_capacity) >= ?) ";
private SearchBuilder<CapacityVO> _hostIdTypeSearch;
private SearchBuilder<CapacityVO> _hostOrPoolIdSearch;
private final SearchBuilder<CapacityVO> _hostIdTypeSearch;
private final SearchBuilder<CapacityVO> _hostOrPoolIdSearch;
protected GenericSearchBuilder<CapacityVO, SummedCapacity> SummedCapacitySearch;
private SearchBuilder<CapacityVO> _allFieldsSearch;
protected final StoragePoolDaoImpl _storagePoolDao = ComponentLocator.inject(StoragePoolDaoImpl.class);
private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = "SELECT a.host_id FROM (host JOIN op_host_capacity a ON host.id = a.host_id AND host.cluster_id = ? AND host.type = ? " +
private static final String LIST_HOSTS_IN_CLUSTER_WITH_ENOUGH_CAPACITY = "SELECT a.host_id FROM (host JOIN op_host_capacity a ON host.id = a.host_id AND host.cluster_id = ? AND host.type = ? " +
"AND (a.total_capacity * ? - a.used_capacity) >= ? and a.capacity_type = 1) " +
"JOIN op_host_capacity b ON a.host_id = b.host_id AND b.total_capacity - b.used_capacity >= ? AND b.capacity_type = 0";
private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1 = "SELECT cluster_id FROM `cloud`.`op_host_capacity` WHERE " ;
private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2 = " AND capacity_type = ? GROUP BY cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * ?) ASC";
public CapacityDaoImpl() {
_hostIdTypeSearch = createSearchBuilder();
@ -164,7 +164,7 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
}
@Override
public List<Long> orderClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){
public List<Long> listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
@ -187,27 +187,15 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
try {
pstmt = txn.prepareAutoCloseStatement(sql.toString());
pstmt.setLong(1, id);
if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){
pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU);
pstmt.setFloat(3, cpuOverprovisioningFactor);
pstmt.setLong(4, requiredCpu);
pstmt.setLong(5, id);
pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY);
pstmt.setFloat(7, 1);
pstmt.setLong(8, requiredRam);
pstmt.setFloat(9, cpuOverprovisioningFactor);
}else{
pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_MEMORY);
pstmt.setFloat(3, 1);
pstmt.setLong(4, requiredRam);
pstmt.setLong(5, id);
pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_CPU);
pstmt.setFloat(7, cpuOverprovisioningFactor);
pstmt.setLong(8, requiredCpu);
pstmt.setFloat(9, 1);
}
ResultSet rs = pstmt.executeQuery();
pstmt.setShort(2, CapacityVO.CAPACITY_TYPE_CPU);
pstmt.setFloat(3, cpuOverprovisioningFactor);
pstmt.setLong(4, requiredCpu);
pstmt.setLong(5, id);
pstmt.setShort(6, CapacityVO.CAPACITY_TYPE_MEMORY);
pstmt.setFloat(7, 1);
pstmt.setLong(8, requiredRam);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getLong(1));
}
@ -363,4 +351,41 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
return remove(sc) > 0;
}
@Override
public List<Long> orderClustersByAggregateCapacity(long id, short capacityTypeForOrdering, boolean isZone, float cpuOverprovisioningFactor){
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
StringBuilder sql = new StringBuilder(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1);
if(isZone){
sql.append("data_center_id = ?");
}else{
sql.append("pod_id = ?");
}
sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2);
try {
pstmt = txn.prepareAutoCloseStatement(sql.toString());
pstmt.setLong(1, id);
pstmt.setShort(2, capacityTypeForOrdering);
if(capacityTypeForOrdering == CapacityVO.CAPACITY_TYPE_CPU){
pstmt.setFloat(3, cpuOverprovisioningFactor);
}else{
pstmt.setFloat(3, 1);
}
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getLong(1));
}
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + sql, e);
} catch (Throwable e) {
throw new CloudRuntimeException("Caught: " + sql, e);
}
}
}

View File

@ -458,9 +458,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner {
//look at the aggregate available cpu and ram per cluster
//although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot
//we need clusters having enough cpu AND RAM
//we need clusters having enough cpu AND RAM to host this particular VM and order them by aggregate cluster capacity
if (s_logger.isDebugEnabled()) {
s_logger.debug("Listing clusters that have enough aggregate CPU and RAM capacity under this "+(isZone ? "Zone: " : "Pod: " )+id);
s_logger.debug("Listing clusters in order of aggregate capacity, that have (atleast one host with) enough CPU and RAM capacity under this "+(isZone ? "Zone: " : "Pod: " )+id);
}
String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key());
short capacityType = CapacityVO.CAPACITY_TYPE_CPU;
@ -471,11 +471,22 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner {
if (s_logger.isDebugEnabled()) {
s_logger.debug("CPUOverprovisioningFactor considered: " + cpuOverprovisioningFactor);
}
List<Long> clusterIdswithEnoughCapacity = _capacityDao.orderClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone, cpuOverprovisioningFactor);
List<Long> clusterIdswithEnoughCapacity = _capacityDao.listClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone, cpuOverprovisioningFactor);
if (s_logger.isTraceEnabled()) {
s_logger.trace("ClusterId List having enough aggregate capacity: " + clusterIdswithEnoughCapacity);
s_logger.trace("ClusterId List having enough CPU and RAM capacity: " + clusterIdswithEnoughCapacity);
}
return clusterIdswithEnoughCapacity;
List<Long> clusterIdsOrderedByAggregateCapacity = _capacityDao.orderClustersByAggregateCapacity(id, capacityType, isZone, cpuOverprovisioningFactor);
//only keep the clusters that have enough capacity to host this VM
if (s_logger.isTraceEnabled()) {
s_logger.trace("ClusterId List in order of aggregate capacity: " + clusterIdsOrderedByAggregateCapacity);
}
clusterIdsOrderedByAggregateCapacity.retainAll(clusterIdswithEnoughCapacity);
if (s_logger.isTraceEnabled()) {
s_logger.trace("ClusterId List having enough CPU and RAM capacity & in order of aggregate capacity: " + clusterIdsOrderedByAggregateCapacity);
}
return clusterIdsOrderedByAggregateCapacity;
}