简单案例
一个简单的仿真案例包括一下基本步骤:
- 初始化CloudSim
- 创建数据中心代理
- 创建数据中心、创建主机列表
- 在主机中放置虚拟机
- 创建云任务Cloudlet
- 提交划分的虚拟机列表给代理
- 提交云任务
- 仿真开始
- 获得仿真结果并输出
public class ReducedExample {
public static void main(String[] args) {
// 设置日志级别
//Log.setLevel(ch.qos.logback.classic.Level.WARN);
// 1.初始化CloudSim
CloudSim cloudsim = new CloudSim();
// 2.创建将代表云用户(客户)行事的 Broker。
DatacenterBroker broker0 = new DatacenterBrokerSimple(cloudsim);
// 3.使用特定的 CPU 内核 (PE) 列表创建一个主机.
List<Host> hostList = new ArrayList<>(1);
List<Pe> hostPes = new ArrayList<>(1);
// Uses a PeProvisionerSimple by default to provision PEs for VMs
hostPes.add(new PeSimple(20000));
final long ram = 10000; //in Megabytes
final long storage = 100000; //in Megabytes
final long bw = 100000; //in Megabits/s
// Uses ResourceProvisionerSimple by default for RAM and BW provisioning
// Uses VmSchedulerSpaceShared by default for VM scheduling
Host host0 = new HostSimple(ram, bw, storage, hostPes);
hostList.add(host0);
// 4.使用主机列表创建一个数据中心
// Uses a VmAllocationPolicySimple by default to allocate VMs
Datacenter dc0 = new DatacenterSimple(cloudsim, hostList);
// 5.创建一个 Vm 来运行应用程序 (Cloudlets)。
List<Vm> vmList = new ArrayList<>(1);
// Uses a CloudletSchedulerTimeShared by default to schedule Cloudlets
Vm vm0 = new VmSimple(1000, 1);
vm0.setRam(1000).setBw(1000).setSize(1000);
vmList.add(vm0);
// 6.创建两个要在 Vm 内运行的应用程序(Cloudlet)。
List<Cloudlet> cloudlets = new ArrayList<>(1);
// UtilizationModel defining the Cloudlets use only 50% of any resource all the time
UtilizationModelDynamic utilizationModel = new UtilizationModelDynamic(0.5);
Cloudlet cloudlet0 = new CloudletSimple(10000, 1, utilizationModel);
Cloudlet cloudlet1 = new CloudletSimple(10000, 1, utilizationModel);
cloudlets.add(cloudlet0);
cloudlets.add(cloudlet1);
// 7.请求代理创建 Vms 和 Cloudlets。
// 它将选择 Host 来放置每个 Vm 和一个 Vm 来运行每个 Cloudlet。
broker0.submitVmList(vmList);
broker0.submitCloudletList(cloudlets);
// 8.启动模拟并等待所有 cloudlets 执行,当没有更多事件要处理时会自动停止.
cloudsim.start();
// 9.模拟结束时打印结果
new CloudletsTableBuilder(broker0.getCloudletFinishedList()).build();
}
}
调度策略
虚拟机调度策略
虚拟机调度策略也称之为虚拟机放置策略,即如何将虚拟机放置在数据中心的主机(host)中。
自带的策略:
VmAllocationPolicyFirstFit
VmAllocationPolicyBestFit
VmAllocationPolicyRandom
VmAllocationPolicyRoundRobin
VmAllocationPolicyWorstFit
VmAllocationPolicySimple
例子:
new DatacenterSimple(simulation, hostList, new VmAllocationPolicySimple())
自定义策略:
如何实现自定义的放置策略?只需要继承VmAllocationPolicyAbstract
类,重写defaultFindHostForVm
方法。
例子:
/**
* @Author: mhh
* @Date: 2021/8/10
* @Description: 自定义虚拟机放置算法(随机放置)
*/
public class MyVmAllocationPolicy extends VmAllocationPolicyAbstract {
private final ContinuousDistribution random = new UniformDistr();;
@Override
protected Optional<Host> defaultFindHostForVm(Vm vm) {
final List<Host> hostList = this.getHostList();
// 索引“i”不是用来获取 Host 的位置,而是记录尝试寻找合适主机Host的次数。
for (int i = 0; i < hostList.size(); i++){
final int randomIndex = (int)(random.sample() * hostList.size());
final Host host = hostList.get(randomIndex);
if(host.isSuitableForVm(vm)){
return Optional.of(host);
}
}
return Optional.empty();
}
}
任务调度策略
任务调度策略是指将任务(Cloudlet)委派给某个虚拟机Vm执行。
默认策略
-
DatacenterBrokerSimple
:顺序调度,把一组任务顺序分配给一组虚拟机。 -
DatacenterBrokerBestFit
:选择能够运行给定 Cloudlet 的 PE 数量最少的 VM。 -
DatacenterBrokerFirstFit
:选择能够运行给定 Cloudlet 的 PE 数量最少的第一个VM -
DatacenterBrokerHeuristic
:使用一些启发式方法,来获得提交的 cloudlets 和 Vm 之间的次优映射
自定义策略
有几种方式,简单介绍两种。
方式一
在将任务( Cloudlets)提交给代理(DatacenterBroker)前,手动将任务绑定到指定的虚拟机。
例如:自定义实现顺序分配策略
// 6.创建云任务
cloudletList = createCloudlets();
// 使用自定义的任务分配策略
bindCloudletToVmsSimple();
// 7.提交划分的虚拟机列表到代理
broker0.submitVmList(vmList);
// 8.提交云任务
broker0.submitCloudletList(cloudletList);
/**
* 顺序分配策略:把一组任务顺序分配给一组虚拟机
*/
private void bindCloudletToVmsSimple(){
int vmNumber = vmList.size();
int cloudletNumber = cloudletList.size();
int index = 0;
for (Cloudlet cloudlet : cloudletList) {
cloudlet.setVm(vmList.get(index));
index = (index + 1) % vmNumber;
}
}
方式二
继承DatacenterBrokerSimple
类,重写defaultVmMapper
方法。
例如:
public class DatacenterBrokerBestFit extends DatacenterBrokerSimple {
public DatacenterBrokerBestFit(final CloudSim simulation) {
super(simulation);
}
/**
* 选择能够运行给定 Cloudlet 的 PE 数量最少的 VM
*
*/
@Override
public Vm defaultVmMapper(final Cloudlet cloudlet) {
if (cloudlet.isBoundToVm()) {
return cloudlet.getVm();
}
final Vm mappedVm = getVmCreatedList()
.stream()
.filter(vm -> vm.getExpectedFreePesNumber() >= cloudlet.getNumberOfPes())
.min(Comparator.comparingLong(Vm::getExpectedFreePesNumber))
.orElse(Vm.NULL);
if (mappedVm == Vm.NULL) {
LOGGER.warn("{}: {}: {} (PEs: {}) couldn't be mapped to any suitable VM.",
getSimulation().clockStr(), getName(), cloudlet, cloudlet.getNumberOfPes());
} else {
LOGGER.trace("{}: {}: {} (PEs: {}) mapped to {} (available PEs: {}, tot PEs: {})",
getSimulation().clockStr(), getName(), cloudlet, cloudlet.getNumberOfPes(), mappedVm,
mappedVm.getExpectedFreePesNumber(), mappedVm.getFreePesNumber());
}
return mappedVm;
}
}
CPU调度策略
CloudSim Plus
在两个层面上调度CPU资源:Host
和VM
。
Host层面
在Host层面,host将处理单元(Processor Element,PE)分片划分给运行于host上的各个VM。由于资源被各个VM共享,所以这个调度器称为VmScheduler
。在一个host实例化后,必须设置一个VmScheduler
调度器。
例如:Host层面的CPU资源调度。
Host host = new HostSimple(ram, bw, storage, peList);
host.setRamProvisioner(new ResourceProvisionerSimple())
.setBwProvisioner(new ResourceProvisionerSimple())
.setVmScheduler(new VmSchedulerTimeShared());
VM层面
在VM层面,每个虚拟机将从host那里分配到的资源划分给在虚拟机中运行的各个Cloudlet。由于资源被各个Cloudlets共享,所以这个调度器成称为CloudletScheduler
。在一个VM创建后,必须设置一个CloudletScheduler
调度器。
例如:Vm层面的CPU资源调度。
Vm vm = new VmSimple(i, 1000, VM_PES)
.setRam(512).setBw(1000).setSize(10000)
.setCloudletScheduler(new CloudletSchedulerTimeShared());
默认调度策略
在上述两个层面,有两个默认的调度策略可用:
-
xSpaceShared
:(x代表VmScheduler
或者CloudletScheduler
),Cloudlet或VM所需的PE将被独有地安排。这意味着如果Cloudlet或VM数量大于可用的PE数量,后面到达的Cloudlet或VM将在队列中等待,直到有足够的空闲资源。 -
xTimeShared
:运行中的Cloudlet或VM分时享有可用的PE,所有Cloudlet或VM同时运行。
上述Cloudlet和VM有关策略可以以任何组合形式搭配使用。例如,你可以使用VmSchedulerTimeShared
和 CloudletSchedulerSpaceShared
,或者VmSchedulerTimeShared
和CloudletSchedulerTimeShared
。甚至一个运行了多个虚拟机的Host有多种CloudletScheduler
或者是一个运行了多个Host的Datacenter有多种VmScheduler
也是可能的。
自定义调度策略
如果要自定义调度策略,可以通过继承一个VmScheduler
或者CloudletScheduler
类来实现。
参考