CLOUDSTACK-8181: Introducing a new allocator called firstfitleastconsumed. The purpose of this allocator is to find hosts/pools with least capacity usage (in terms of percentage) within the cluster and use those resources first before others. This allocator can be used changing vm.allocation.algorithm. For hosts it would decide the least consumed host through the setting host.capacityType.to.order.clusters to base the usage on cpu or ram.

Reviewed-by: Prachi
This commit is contained in:
Nitin Mehta 2015-01-26 10:41:46 -08:00
parent 29aeed71fc
commit abf4e5c646
5 changed files with 105 additions and 1 deletions

View File

@ -56,4 +56,6 @@ public interface CapacityDao extends GenericDao<CapacityVO, Long> {
List<Long> listClustersCrossingThreshold(short capacityType, Long zoneId, String configName, long computeRequested);
float findClusterConsumption(Long clusterId, short capacityType, long computeRequested);
List<Long> orderHostsByFreeCapacity(Long clusterId, short capacityType);
}

View File

@ -98,6 +98,8 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
private static final String ORDER_PODS_BY_AGGREGATE_OVERCOMMIT_CAPACITY =
"SELECT capacity.pod_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id) WHERE data_center_id=? AND capacity_type = ? AND cluster_details.name = ? GROUP BY capacity.pod_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC";
private static final String ORDER_HOSTS_BY_FREE_CAPACITY = "SELECT host_id, SUM(total_capacity - (used_capacity+reserved_capacity))/SUM(total_capacity) FROM `cloud`.`op_host_capacity` WHERE "
+ " cluster_id = ? AND capacity_type = ? GROUP BY host_id ORDER BY SUM(total_capacity - (used_capacity+reserved_capacity))/SUM(total_capacity) DESC ";
private static final String LIST_CAPACITY_BY_RESOURCE_STATE =
"SELECT capacity.data_center_id, sum(capacity.used_capacity), sum(capacity.reserved_quantity), sum(capacity.total_capacity), capacity_capacity_type "
@ -857,6 +859,29 @@ public class CapacityDaoImpl extends GenericDaoBase<CapacityVO, Long> implements
}
}
@Override
public List<Long> orderHostsByFreeCapacity(Long clusterId, short capacityTypeForOrdering){
TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
StringBuilder sql = new StringBuilder(ORDER_HOSTS_BY_FREE_CAPACITY);
try {
pstmt = txn.prepareAutoCloseStatement(sql.toString());
pstmt.setLong(1, clusterId);
pstmt.setShort(2, capacityTypeForOrdering);
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);
}
}
@Override
public List<Long> listPodsByHostCapacities(long zoneId, int requiredCpu, long requiredRam, short capacityType) {
TransactionLegacy txn = TransactionLegacy.currentTxn();

View File

@ -35,6 +35,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import com.cloud.capacity.Capacity;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.deploy.DeploymentPlan;
@ -72,6 +74,8 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
protected String _allocationAlgorithm = "random";
@Inject
DiskOfferingDao _diskOfferingDao;
@Inject
CapacityDao _capacityDao;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
@ -100,6 +104,39 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
return reOrder(pools, vmProfile, plan);
}
protected List<StoragePool> reorderPoolsByCapacity(DeploymentPlan plan,
List<StoragePool> pools) {
Long clusterId = plan.getClusterId();
short capacityType;
if(pools != null && pools.size() != 0){
capacityType = pools.get(0).getPoolType().isShared() == true ?
Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED : Capacity.CAPACITY_TYPE_LOCAL_STORAGE;
} else{
return null;
}
List<Long> poolIdsByCapacity = _capacityDao.orderHostsByFreeCapacity(clusterId, capacityType);
if (s_logger.isDebugEnabled()) {
s_logger.debug("List of pools in descending order of free capacity: "+ poolIdsByCapacity);
}
//now filter the given list of Pools by this ordered list
Map<Long, StoragePool> poolMap = new HashMap<Long, StoragePool>();
for (StoragePool pool : pools) {
poolMap.put(pool.getId(), pool);
}
List<Long> matchingPoolIds = new ArrayList<Long>(poolMap.keySet());
poolIdsByCapacity.retainAll(matchingPoolIds);
List<StoragePool> reorderedPools = new ArrayList<StoragePool>();
for(Long id: poolIdsByCapacity){
reorderedPools.add(poolMap.get(id));
}
return reorderedPools;
}
protected List<StoragePool> reorderPoolsByNumberOfVolumes(DeploymentPlan plan, List<StoragePool> pools, Account account) {
if (account == null) {
return pools;
@ -144,6 +181,8 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
Collections.shuffle(pools);
} else if (_allocationAlgorithm.equals("userdispersing")) {
pools = reorderPoolsByNumberOfVolumes(plan, pools, account);
} else if(_allocationAlgorithm.equals("firstfitleastconsumed")){
pools = reorderPoolsByCapacity(plan, pools);
}
return pools;
}

View File

@ -32,6 +32,9 @@ import org.springframework.stereotype.Component;
import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.capacity.CapacityManager;
import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.configuration.Config;
import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO;
import com.cloud.dc.dao.ClusterDao;
@ -89,6 +92,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
ServiceOfferingDetailsDao _serviceOfferingDetailsDao;
@Inject
CapacityManager _capacityMgr;
@Inject
CapacityDao _capacityDao;
boolean _checkHvm = true;
protected String _allocationAlgorithm = "random";
@ -235,6 +240,8 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
Collections.shuffle(hosts);
} else if (_allocationAlgorithm.equals("userdispersing")) {
hosts = reorderHostsByNumberOfVms(plan, hosts, account);
}else if(_allocationAlgorithm.equals("firstfitleastconsumed")){
hosts = reorderHostsByCapacity(plan, hosts);
}
if (s_logger.isDebugEnabled()) {
@ -318,6 +325,37 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
return suitableHosts;
}
// Reorder hosts in the decreasing order of free capacity.
private List<? extends Host> reorderHostsByCapacity(DeploymentPlan plan, List<? extends Host> hosts) {
Long clusterId = plan.getClusterId();
//Get capacity by which we should reorder
String capacityTypeToOrder = _configDao.getValue(Config.HostCapacityTypeToOrderClusters.key());
short capacityType = CapacityVO.CAPACITY_TYPE_CPU;
if("RAM".equalsIgnoreCase(capacityTypeToOrder)){
capacityType = CapacityVO.CAPACITY_TYPE_MEMORY;
}
List<Long> hostIdsByFreeCapacity = _capacityDao.orderHostsByFreeCapacity(clusterId, capacityType);
if (s_logger.isDebugEnabled()) {
s_logger.debug("List of hosts in descending order of free capacity in the cluster: "+ hostIdsByFreeCapacity);
}
//now filter the given list of Hosts by this ordered list
Map<Long, Host> hostMap = new HashMap<Long, Host>();
for (Host host : hosts) {
hostMap.put(host.getId(), host);
}
List<Long> matchingHostIds = new ArrayList<Long>(hostMap.keySet());
hostIdsByFreeCapacity.retainAll(matchingHostIds);
List<Host> reorderedHosts = new ArrayList<Host>();
for(Long id: hostIdsByFreeCapacity){
reorderedHosts.add(hostMap.get(id));
}
return reorderedHosts;
}
private List<? extends Host> reorderHostsByNumberOfVms(DeploymentPlan plan, List<? extends Host> hosts, Account account) {
if (account == null) {
return hosts;

View File

@ -980,7 +980,7 @@ public enum Config {
String.class,
"vm.allocation.algorithm",
"random",
"'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit' : Order in which hosts within a cluster will be considered for VM/volume allocation.",
"'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', 'firstfitleastconsumed' : Order in which hosts within a cluster will be considered for VM/volume allocation.",
null),
VmDeploymentPlanner(
"Advanced",