当前位置: 首页 > news >正文

从官方示例学习使用 CloudSim

0 引言

在 CloudSim 源代码中,提供了15个样例(cloudsim-7.0.1\modules\cloudsim-examples\src\main\java\org\cloudbus\cloudsim\examples),他们分别是:

序号文件名官方介绍翻译简记
1CloudSimExample1A simple example showing how to create a data center with one host and run one cloudlet on it.一个简单的示例,展示了如何构建一个仅包含一台主机的数据中心,并在其上运行一个云单元。1Dc 1H 1Cl 1U
2CloudSimExample2A simple example showing how to create a datacenter with one host and run two cloudlets on it. The cloudlets run in VMs with the same MIPS requirements. The cloudlets will take the same time to complete the execution.一个简单的示例展示了如何创建一个仅包含一台主机的数据中心,并在其上运行两个云单元。这些云单元在具有相同 MIPS 要求的虚拟机中运行。这些云单元完成执行所需的时间将完全相同。1Dc 1H 2Cl 1U
3CloudSimExample3A simple example showing how to createa datacenter with two hosts and run two cloudlets on it. The cloudlets run in VMs with different MIPS requirements. The cloudlets will take different time to complete the execution depending on the requested VM performance.一个简单的示例展示了如何创建一个包含两台主机的数据中心,并在其上运行两个云片。这些云片在具有不同 MIPS 要求的虚拟机中运行。根据所请求的虚拟机性能,这些云片完成执行所需的时间会有所不同。1Dc 2H 2Cl 1U
4CloudSimExample4A simple example showing how to create two datacenters with one host each and run two cloudlets on them.一个简单的示例展示了如何创建两个分别由一台主机管理的数据中心,并在它们上运行两个云服务单元。2Dc 2H 2Cl 1U
5CloudSimExample5A simple example showing how to create two datacenters with one host each and run cloudlets of two users on them.一个简单的示例展示了如何创建两个分别由一台主机支撑的数据中心,并在这些数据中心上运行两个用户的云服务实例。2Dc 1H 2Cl 2U
6CloudSimExample6An example showing how to create scalable simulations.一个展示如何创建可扩展模拟的示例。
7CloudSimExample7An example showing how to pause and resume the simulation, and create simulation entities (a DatacenterBroker in this example) dynamically.一个示例展示了如何暂停和恢复模拟操作,以及如何动态创建模拟实体(在本示例中为“数据中心代理”)。
8CloudSimExample8An example showing how to create simulation entities (a DatacenterBroker in this example) in run-time using a globar manager entity (GlobalBroker).一个示例展示了如何在运行时使用全局管理实体(全局代理)来创建模拟实体(在此示例中为数据中心代理)。
9CloudSimExample9A simple example showing the 2 cloudlet scheduling models: time-shared and space-shared.一个简单的示例展示了两种云单元调度模型:时间共享模式和空间共享模式。
10CloudSimMultiExtensionExample1A simple example showing the use of containers (ContainerCloudSim) and Vms (base CloudSim) in the same contexts.一个简单的示例展示了在相同场景下容器(ContainerCloudSim)和虚拟机(基础的CloudSim)的使用情况。
11CloudSimMultiExtensionExample2(详见源文件)一个示例程序,展示如何在 CloudSim 中构建包含多个主机和虚拟机的网络数据中心,并运行一个具有菱形依赖结构(A→B、A→C、B/C→D)的工作流应用。
12CloudSimMultiExtensionPaperExample(详见源文件)一个示例程序,展示如何在 CloudSim 中构建包含两台主机、四个虚拟机和一个容器的网络数据中心,并运行一个简单的串行工作流(A→B),用于演示容器与虚拟机间的数据传输和网络通信影响。
13CloudSimMultiExtensionPaperExampleRunner(详见源文件)一个用于 CloudSim 7G 论文实验的高级示例程序,展示如何构建包含多层交换机、多个主机、虚拟机与容器的复杂数据中心,并在其中运行可周期触发的串行工作流(A→B),以评估不同虚拟化层次和网络配置下的性能与数据传输行为。
14DiamondAppMultiExtensionExample一个批量实验示例,展示如何自动运行多种虚拟化与网络配置下的 CloudSim 模拟以评估系统性能差异。
15TestScheduledResource一个测试示例,展示如何使用 ScheduledResource 在 CloudSim 中实现事件的定时与延迟调度机制。

俗话说得好:“工欲善其事,必先利其器”。要想利用 CloudSim 这个平台去验证自己的策略,就必须要先学会使用它。这次我们就浏览这 15 个例子,从中由易到难地学会使用 CloudSim。

2 入门示例 CloudSimExample1

首先,我们先看一个最简单的示例 CloudSimExample1:如何构建一个仅包含一台主机的数据中心,并在其上运行一个云任务。我们详细阅读这段代码,主要了解平台使用过程,相关组件如何协同工作。

/** 声明文件所在包(目录结构要一致) */
package org.cloudbus.cloudsim.examples;
/** 从 Java 标准库导入相关类 */
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
/** 导入 CloudSim 框架里的类 */
import org.cloudbus.cloudsim.Cloudlet;
import org.cloudbus.cloudsim.CloudletSchedulerTimeShared;
import org.cloudbus.cloudsim.Datacenter;
import org.cloudbus.cloudsim.DatacenterBroker;
import org.cloudbus.cloudsim.DatacenterCharacteristics;
import org.cloudbus.cloudsim.Host;
import org.cloudbus.cloudsim.Log;
import org.cloudbus.cloudsim.Pe;
import org.cloudbus.cloudsim.Storage;
import org.cloudbus.cloudsim.UtilizationModel;
import org.cloudbus.cloudsim.UtilizationModelFull;
import org.cloudbus.cloudsim.Vm;
import org.cloudbus.cloudsim.VmAllocationPolicySimple;
import org.cloudbus.cloudsim.VmSchedulerTimeShared;
import org.cloudbus.cloudsim.core.CloudSim;
import org.cloudbus.cloudsim.provisioners.BwProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.RamProvisionerSimple;

核心组件有:Cloudlet(任务)、VM(虚拟机)、Host(物理主机)、Datacenter(数据中心)和DatacenterBroker(调度代理)等。每个类负责仿真中的不同实体或功能。

public class Practice {/** 声明将使用到的变量 */public static DatacenterBroker broker; // 调度代理private static List<Cloudlet> cloudletList; // 云任务列表private static List<VM> vmList; // 虚拟机列表
	public static void main(String[] args) {/** 调用 CloudSim 的 Log 工具打印一行日志 */Log.println("Starting CloudSimExample1...");
		try {/** 1 初始化 CloudSim */int num_user = 1; // 设置云用户的数量Calendar calendar = Calendar.getInstance(); // 日历的字段已用当前日期和时间初始化,CloudSim 需要一个时间基准boolean trace_flag = false; // 设置不跟踪事件CloudSim.init(num_user, calendar, trace_flag); // 方法调用,初始化 CloudSim 框架,包括事件队列、实体注册等仿真基础设施
			/** 2 创建 Datacenter */Datacenter datacenter0 = createDatacenter("Datacenter_0"); // 调用 createDatacente 方法创建一个数据中心实例,返回 Datacenter 对象并赋给 datacenter0
			/** 3 创建 Broker */broker = new DatacenterBroker("Broker"); //调用类的构造函数,初始化对象状态int brokerId = broker.getId(); // 返回该实体在仿真中的整数 ID 保存为 brokerID
            /** 4 创建 VM */// 4.1 创建存储列表vmList = new ArrayList<>(); // 创建一个新的空动态数组(ArrayList),并把它赋给变量 vmlist// 4.2 添加虚拟机描述int vmid = 0; // 虚拟机 IDint mips = 1000; // 每个处理器的 MIPS(百万指令/秒),性能标识long size = 10000; // image size (MB) 镜像/磁盘大小(MB)int ram = 512; // vm memory (MB) 内存(MB)long bw = 1000; // 带宽(单位不严格,在仿真里表示带宽容量)int pesNumber = 1; // number of cpus 该 VM 申请的处理单元数(CPU core 数)String vmm = "Xen"; // VMM name 虚拟机管理程序// 4.3 创建虚拟机Vm vm = new Vm(vmid, brokerId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared()); // 最后一个参数决定了在一个 VM 上运行的多个 Cloudlet 如何共享该 VM 的 CPU// 4.4 添加虚拟机到虚拟机列表vmList.add(vm); // 4.5 将虚拟机列表提交给 brokerbroker.submitGuestList(vmList); 
            /** 5 创建 Cloudlet */// 5.1 定义 Cloudlet(仿真任务) 的属性int id = 0; // 设置任务 IDlong length = 400000; // 任务长度(单位为指令数量/长度,CloudSim 以 MIPS 与 length 计算执行时间)// 5.2 用于模拟 I/O 引起的带宽/存储使用long fileSize = 300; // 输入文件大小long outputSize = 300; // 输出文件大小// 5.3资源利用模型UtilizationModel utilizationModel = new UtilizationModelFull();Cloulet cloudlet = new Cloudlet(id, length, pesNumber, fileSize, outputSize,utilizationModel, utilizationModel); // 用 UtilizationModelFull() 表示在整个执行期间 CPU/内存/带宽都被 100% 使用(即持续占用)// 5.4 构造 Cloudlet 对象cloudlet.setUserId(brokerId); // 告诉 Cloudlet 属于哪个用户代理(broker)cloudlet.setGuestId(vmid); // 把 Cloudlet 绑定到哪个 VM(vm id)// 5.5 把 Cloudlet 加入 cloudletListcloudletList.add(cloudlet);// 5.6 提交 Cloudlet 列表给 broker,由 broker 负责把任务分配到 VM 上并发送调度请求到数据中心broker.submitCloudletList(cloudletList);
            // 启动仿真引擎CloudSim.startSimulation(); // 启动CloudSim.stopSimulation(); // 停止。通常你会在 startSimulation() 返回后调用 stopSimulation()
            // 最后:打印结果// 仿真结束后,从 broker 获取已完成的 Cloudlet 列表 getCloudletReceivedList()(这些 Cloudlet 已经执行完并返回结果)List<Cloudlet> newlist = broker.getCloudletReceivedList();printCloudletList(newlist);Log.println("CloudSimExample1 finished!");
        // 异常处理} catch (Exception e) {e.printStackTrace();Log.println("Unwanted errors happen");}}

以上,就是使用 CloudSim 框架的步骤。可总结记忆为”CDBVC“——初始化 CloudSim、创建 Datacenter、创建 Broker、创建 Vm、创建 Cloudlet。下面是两个方法 createDatacenter 和 printCloudletList,分别用来创建数据中心(主机)和打印云任务成功执行的情况总结。

private static Datacenter createDatacenter(String name) {// 1 创建一个列表来存储主机List<Host> hostList = new ArrayList<>(); // hostList 将保持数据中心的主机(Host)// 2 一个 Host 包含若干个 PE(Processing Elements)List<Pe> peList = new ArrayList<>();int mips = 1000; // 定义 PE 的性能:1000 MIPS// 3 创建一个 Pe(id = 0),并传入一个 PeProvisionerSimple(负责为 VM 分配 PE 的 MIPS)peList.add(new Pe(0, new PeProvisionerSimple(mips))); // 4 创建主机及其 ID 和 PE 列表,并将其添加到机器列表中int hostId = 0;int ram = 2048; // host memory (MB)long storage = 1000000; // host storage 磁盘存储int bw = 10000; // 带宽hostList.add(new Host(hostId,new RamProvisionerSimple(ram), // 内存分配器new BwProvisionerSimple(bw), // 带宽分配器storage,peList,new VmSchedulerTimeShared(peList) // VM 调度器)); // 5 创建数据中心特征对象String arch = "x86"; // system architecture 系统架构String os = "Linux"; // operating system 操作系统String vmm = "Xen"; // 虚拟化管理程序名称(只是描述性信息,某些策略可能用到)double time_zone = 10.0; // time zone this resource located 时区(仿真中用于计费或时间显示,不是系统时区)// 5.1 各类资源的计费参数(仿真财务模块可以使用)double cost = 3.0; // the cost of using processing in this resource 使用此资源处理的成本double costPerMem = 0.05; // the cost of using memory in this resource 内存double costPerStorage = 0.001; // the cost of using storage in this resource 存储double costPerBw = 0.0; // the cost of using bw in this resource 带宽// 5.2 存储设备列表LinkedList<Storage> storageList = new LinkedList<>(); // we are not adding SAN devices by now// 5.3 构造 DatacenterCharacteristics 实例,封装数据中心的描述信息(包括 hostList)DatacenterCharacteristics characteristics = new DatacenterCharacteristics(arch, os, vmm, hostList, time_zone, cost, costPerMem,costPerStorage, costPerBw);// 6. 创建 PowerDatacenter 对象Datacenter datacenter = null;try {datacenter = new Datacenter(name, characteristics, new VmAllocationPolicySimple(hostList), storageList, 0);} catch (Exception e) {e.printStackTrace();}return datacenter;}
private static void printCloudletList(List<Cloudlet> list) {int size = list.size();  // 获取任务列表的大小Cloudlet cloudlet;       // 声明一个Cloudlet变量用于循环中临时存储String indent = "    ";  // 定义缩进字符串,用于格式化输出对齐// 输出表头和分隔线Log.println();Log.println("========== OUTPUT ==========");// 打印列标题:任务ID、状态、数据中心ID、虚拟机ID、执行时间、开始时间、完成时间Log.println("Cloudlet ID" + indent + "STATUS" + indent+ "Data center ID" + indent + "VM ID" + indent + "Time" + indent+ "Start Time" + indent + "Finish Time");// 创建数字格式化器,限制小数位数为两位DecimalFormat dft = new DecimalFormat("###.##");// 遍历所有云任务for (Cloudlet value : list) {cloudlet = value;  // 获取当前云任务对象// 打印任务ID(带缩进格式化)Log.print(indent + cloudlet.getCloudletId() + indent + indent);// 检查任务状态是否为成功完成if (cloudlet.getStatus() == Cloudlet.CloudletStatus.SUCCESS) {Log.print("SUCCESS");  // 打印状态信息// 打印任务的详细信息:// - cloudlet.getResourceId(): 任务运行所在的数据中心ID// - cloudlet.getGuestId(): 任务运行所在的虚拟机ID  // - cloudlet.getActualCPUTime(): 任务实际消耗的CPU时间// - cloudlet.getExecStartTime(): 任务开始执行的时间// - cloudlet.getExecFinishTime(): 任务完成的时间Log.println(indent + indent + cloudlet.getResourceId()+ indent + indent + indent + cloudlet.getGuestId()+ indent + indent+ dft.format(cloudlet.getActualCPUTime()) + indent+ indent + dft.format(cloudlet.getExecStartTime())+ indent + indent+ dft.format(cloudlet.getExecFinishTime()));}// 注意:这里没有处理失败或其他状态的任务,只有成功状态的任务会被详细输出}
}

这里主要说明两个调度管理器,和他们主要的调度策略:

VmScheduler:Host 调度器,管理 VM 之间的 CPU 资源分配

  • VmSchedulerTimeShared:所有 VM 可以同时共享同一 CPU 核心的时间片(并发执行)
  • VmSchedulerSpaceShared:同一时间一个 CPU 核心只能分配给一个VM使用

CloudletScheduler:VM 调度器,管理 Cloudlet 之间的 CPU 资源分配

  • CloudletSchedulerTimeShared:所有 Cloudlet 可以同时共享 CPU 时间片(并发执行)
  • CloudletSchedulerSpaceShared:每个 Cloudlet 独占一个或多个 CPU 核心

运行示例1,得到结果:

Starting CloudSimExample1...
Initialising...
Starting CloudSim version 7.0
0.0: Datacenter_0 is starting...
0.0: Broker is starting...
Entities started.
0.0: Broker: Cloud Resource List received with 1 datacenter(s)
0.0: Broker: Trying to Create Vm #0 in Datacenter_0
0.0: Datacenter_0.guestAllocator: Vm #0 has been allocated to Host #0
0.01: Broker: Vm #0 has been created in Datacenter #2, Host #0
0.01: Broker: Sending Cloudlet #0 to Vm #0
400.01: Broker: Cloudlet #0 return received
400.01: Broker: The number of finished Cloudlets is:1
400.01: Broker: All Cloudlets executed. Finishing...
400.01: Broker: Destroying Vm #0
400.01: Broker is shutting down...
400.01: Simulation: No more future events
400.01: CloudInformationService is shutting down...
400.01: CloudInformationService: Notify all CloudSim entities for shutting down.
400.01: Datacenter_0 is shutting down...
400.01: Broker is shutting down...
Simulation completed.
Simulation completed.========== OUTPUT ==========
Cloudlet ID    STATUS    Data center ID    VM ID    Time    Start Time    Finish Time0        SUCCESS        2            0        400        0.01        400.01
CloudSimExample1 finished!

这段结果表示 CloudSim 成功完成了云计算模拟过程。模拟从初始化开始,系统创建了一个数据中心(Datacenter_0)和一个资源代理(Broker)。代理在数据中心中创建了一台虚拟机(VM #0),并将一个任务(Cloudlet #0)提交给该虚拟机执行。任务从时间 0.01 开始运行,持续 400 个时间单位后在时间 400.01 完成,执行结果为成功(SUCCESS)。随后,代理销毁虚拟机并关闭模拟。整个过程说明系统各组件运行正常,任务顺利执行完毕,模拟顺利结束。

3 对 Dc、H、Cl 和 U 进行简单的数量增加

在上述的CloudSimExample1中,使用到的 Datacenter (Dc)、Host (H)、Cloudlet (Cl) 和 User (U) 的数量都是1。

CloudSimExample2

CloudSimExample2 在示例1的基础上,增加了1个 Cloudlet:

id++;
Cloudlet cloudlet2 = new Cloudlet(id, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel);
cloudlet2.setUserId(brokerId);

由于 Cloudlet 依赖于 VM 执行,所以也增加了一个 VM:

vmid++;
Vm vm2 = new Vm(vmid, brokerId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerSpaceShared());

并将两个虚拟机和两个云任务一一绑定:

broker.bindCloudletToVm(cloudlet1.getCloudletId(),vm1.getId());
broker.bindCloudletToVm(cloudlet2.getCloudletId(),vm2.getId());

CloudSimExample3

CloudSimExample3 在 CloudSimExample2 的基础上,给 Datacenter 增加了1台 Host:

List<Pe> peList2 = new ArrayList<>();peList2.add(new Pe(0, new PeProvisionerSimple(mips)));hostId++;hostList.add(new Host(hostId,new RamProvisionerSimple(ram),new BwProvisionerSimple(bw),storage,peList2,new VmSchedulerSpaceShared(peList2))); // This is our second machine

并修改第2个 VM 的性能:

vmid++;
Vm vm2 = new Vm(vmid, brokerId, mips * 2, pesNumber, ram, bw, size, vmm, new CloudletSchedulerSpaceShared());

由运行结果:

Starting CloudSimExample3...
Initialising...
Starting CloudSim version 7.0
0.0: Datacenter_0 is starting...
0.0: Broker is starting...
Entities started.
0.0: Broker: Cloud Resource List received with 1 datacenter(s)
0.0: Broker: Trying to Create Vm #0 in Datacenter_0
0.0: Broker: Trying to Create Vm #1 in Datacenter_0
0.0: Datacenter_0.guestAllocator: Vm #0 has been allocated to Host #0
0.0: Datacenter_0.guestAllocator: Vm #1 has been allocated to Host #1
0.01: Broker: Vm #0 has been created in Datacenter #2, Host #0
0.01: Broker: Vm #1 has been created in Datacenter #2, Host #1
0.01: Broker: Sending Cloudlet #0 to Vm #0
0.01: Broker: Sending Cloudlet #1 to Vm #1
80.01: Broker: Cloudlet #1 return received
80.01: Broker: The number of finished Cloudlets is:1
160.01: Broker: Cloudlet #0 return received
160.01: Broker: The number of finished Cloudlets is:2
160.01: Broker: All Cloudlets executed. Finishing...
160.01: Broker: Destroying Vm #0
160.01: Broker: Destroying Vm #1
160.01: Broker is shutting down...
160.01: Simulation: No more future events
160.01: CloudInformationService is shutting down...
160.01: CloudInformationService: Notify all CloudSim entities for shutting down.
160.01: Datacenter_0 is shutting down...
160.01: Broker is shutting down...
Simulation completed.
Simulation completed.========== OUTPUT ==========
Cloudlet ID    STATUS    Data center ID    VM ID    Time    Start Time    Finish Time1        SUCCESS        2            1        80        0.01        80.010        SUCCESS        2            0        160        0.01        160.01
CloudSimExample3 finished!

可以看出,系统首先完成初始化,创建了一个数据中心(Datacenter_0)和一个代理(Broker)。随后,Broker 在该数据中心中创建了两台虚拟机(VM #0 和 VM #1),分别被分配到主机 Host #0 和 Host #1 上。创建完成后,代理将两个任务(Cloudlet #0 和 Cloudlet #1)分别提交给两台虚拟机执行。从结果可以看到,任务 Cloudlet #1 在时间 0.01 开始执行,并在 80.01 时完成,执行时间为 80 个时间单位;任务 Cloudlet #0 同样在 0.01 开始执行,但在 160.01 时完成,执行时间为 160 个时间单位。两者均成功完成(SUCCESS),说明两个虚拟机同时独立地运行任务,没有相互等待或竞争资源。最后,所有任务执行结束,Broker 销毁虚拟机并关闭模拟,系统顺利结束运行。

这里面的两台虚拟机分别被分配到两个主机上的关键就是 VmAllocationPolicySimple。在 CloudSim 中,VmAllocationPolicySimple 默认采用 “第一个可行主机” 策略(first-fit)。也就是说,它会从 hostList 的第一个开始检查是否能放下 VM:如果 Host #0 有足够的资源,就放在 Host #0;如果放不下,就放在 Host #1。

CloudSimExample4

CloudSimExample4 在 CloudSimExample2 的基础上,增加了一个 Datacenter:

Datacenter datacenter0 = createDatacenter("Datacenter_0");
Datacenter datacenter1 = createDatacenter("Datacenter_1");

每个 Datacenter 都有一台 Host,并且为两个 Cloudlet 各分配一个 VM。两个 Cloudlet 运行在两个 Datacenter,他们相互独立。

CloudSimExample5

在前四个示例中,所涉及到的 User 的数量都是 1,而在 CloudSimExample5 中,增加了一个用户。多用户,就涉及到了多代理,所以 CloudSimExample5 中的 Broker 的数量是2:

public static DatacenterBroker broker1;
public static DatacenterBroker broker2;

每个 Broker 独立完成以下步骤:获取资源列表(Datacenter 列表)、尝试在可用的 Datacenter 中创建 VM、若失败,尝试下一个 Datacenter 和分配 Cloudlet 到成功创建的 VM。在示例5的日志中:

0.0: Broker1: Trying to Create Vm #0 in Datacenter_0
0.0: Broker2: Trying to Create Vm #0 in Datacenter_0

两个 Broker 几乎同时尝试在同一个 Datacenter(Datacenter_0)上创建 VM。但是 Datacenter_0 只有一个 Host,且采用 SpaceShared 策略,意味着一个 Host 上的一个 PE 只能分配给一个 VM。于是:

0.0[GuestScheduler.guestCreate] Allocation of Vm #0 failed by Number of PEs or MIPS

表示第二个 VM 创建失败,因为 CPU (PE) 已被占用。Broker2 随后自动尝试下一个数据中心:

0.01: Broker2: Trying to Create Vm #0 in Datacenter_1

并成功。这正是多用户环境中“资源竞争 + 调度重试”的典型过程。Datacenter_0 为什么拒绝第二个 VM?关键在这一行:

new VmSchedulerSpaceShared(peList)

这意味着 每个处理单元(PE)只能分配给一个 VM,而每个 Host 只有 1 个 PE,所以,一个 Host 一次只能运行 1 个 VM。当第一个 Broker 占用了 Datacenter_0 的唯一主机后,第二个 Broker 就必须找其他数据中心。示例5的意义在于展示在多用户、多数据中心环境下,CloudSim 如何实现资源发现、分配与隔离。与单用户示例相比,它体现了 CloudSim 的多代理并发调度机制,即当多个用户同时竞争有限资源时,系统能自动选择可用数据中心并独立执行任务。如果第二个 Broker 没有其他可用数据中心,它的 VM 创建就会失败;由于没有 VM,它的 Cloudlet 也不会执行。模拟不会报错,但输出结果中该 Broker 的 Cloudlet 列表会是空的。

4 进阶

CloudSimExample6

CloudSimExample6 展示了如何创建可扩展模拟。可扩展,就是指可以方便地增加 VM 数量、Cloudlet 数量、Host 数量、或 Datacenter 数量,而不需要修改核心逻辑代码,主要实现方法是通过:结构化函数划分(createVM / createCloudlet / createDatacenter)、循环批量创建资源以及 TimeShared 调度策略(允许资源共享)。

CloudSimExample7

CloudSimExample7 演示了如何暂停(pause)与恢复(resume)模拟,并且在模拟运行中 动态创建新的模拟实体(DatacenterBroker)。模拟开始后:

  1. 第一个用户(Broker_0)创建并提交了 5 个 VM 和 10 个 Cloudlet;
  2. 模拟运行一段时间;
  3. 在仿真时钟到达 200 的时候,系统暂停(pause);
  4. 暂停期间,新创建一个 Broker_1
  5. Broker_1 创建新的 VM 和 Cloudlet;
  6. 恢复(resume)模拟,新的 Broker 开始参与;
  7. 仿真继续运行直到所有任务完成。

下段代码创建了一个独立的线程,用于在后台监听并操作仿真:

Runnable monitor = () -> {CloudSim.pauseSimulation(200);...
};
new Thread(monitor).start();

在这个线程中, CloudSim.pauseSimulation(200); 表示在仿真时钟到达 200.0 时自动暂停。接着使用一个小循环,不断检查 CloudSim 是否真的暂停成功。

while (true) {if (CloudSim.isPaused()) {break;}Thread.sleep(100);
}

因为仿真是异步执行的,所以要等暂停生效。当暂停成功后,会打印日志:

Log.println("\n\n\n" + CloudSim.clock() + ": The simulation is paused for 5 sec \n\n");

然后用 Thread.sleep(5000); 表示现实中暂停 5 秒钟(不是模拟时间,而是真实时间)。这 5 秒期间,代码模拟“动态插入新用户”,即执行:

broker1 = new DatacenterBroker("Broker_1");
int brokerId1 = broker1.getId();

然后为新 Broker 创建资源:

vmlist = createVM(brokerId1, 5, 100);
cloudletList = createCloudlet(brokerId1, 10, 100);
broker1.submitGuestList(vmlist);
broker1.submitCloudletList(cloudletList);

这里新创建的 VM 和 Cloudlet 的 ID 从 100 开始(idShift = 100),以避免与第一个 Broker 的资源冲突。当完成资源添加后:

CloudSim.resumeSimulation();

表示恢复仿真运行。从这一刻开始,新创建的 Broker_1 也会进入仿真环境,像 Broker_0 一样参与任务调度。那么CloudSim 内部是怎么实现暂停/恢复的?在 CloudSim 框架内部,CloudSim.pauseSimulation(time) 会在事件队列中注册一个“暂停事件”。当仿真时钟推进到 time 时,这个事件被触发,模拟线程进入“暂停状态”(paused = true),外部代码可以安全地创建新实体、添加新任务。当调用 CloudSim.resumeSimulation() 时,仿真线程会被唤醒,继续执行剩余事件。

CloudSimExample8

CloudSimExample8 的核心目的是展示如何在仿真运行过程中,通过一个全局管理实体(GlobalBroker)动态创建新的模拟实体(DatacenterBroker)。在云模拟中,可能希望在仿真进行中引入新的用户(Broker)或者任务,而不是在仿真初始化时就全部确定。因此,定义一个全局管理实体 GlobalBroker,由它在仿真过程中触发事件,动态创建新的 DatacenterBroker 并提交 VM 和 Cloudlet。GlobalBroker 继承自 SimEntity(CloudSim 中的基本仿真实体类),其主要功能:

  1. 接收事件:通过 processEvent(SimEvent ev) 方法处理事件。
  2. 启动调度:通过 startEntity() 方法在仿真开始时安排一个事件。
  3. 动态创建 Broker:在事件触发时,创建新的 DatacenterBroker,并分配资源。

GlobalBroker 启动时,会向自己发送一个事件:

public void startEntity() {super.startEntity();schedule(getId(), 200, ExampleTags.CREATE_BROKER); // 延迟时间为 200(仿真时间单位),事件类型是 ExampleTags.CREATE_BROKER
}

这意味着在仿真时钟到 200 时,GlobalBroker 会处理这个事件。当事件触发时:

public void processEvent(SimEvent ev) {if (ev.getTag() == ExampleTags.CREATE_BROKER) {setBroker(createBroker(super.getName() + "_"));setVmList(createVM(getBroker().getId(), 5, 100));setCloudletList(createCloudlet(getBroker().getId(), 10, 100));broker.submitGuestList(getVmList());broker.submitCloudletList(getCloudletList());CloudSim.resumeSimulation();} else {Log.println(getName() + ": unknown event type");}
}

先创建一个新的 DatacenterBroker,再为该 Broker 创建新的 VM 和 Cloudlet,接着将这些资源提交给 Broker,最后调用 CloudSim.resumeSimulation () 继续仿真,这样便实现了在仿真运行中动态创建新用户的目标。为什么不直接在 main 中创建呢?因为在 CloudSim 中,main 方法仅在仿真初始化阶段执行一次,而若要在仿真运行过程中动态增加实体,就必须通过 SimEntity 和事件机制 —— 这是由 CloudSim 作为事件驱动的离散仿真的特性所决定的,而 GlobalBroker 的事件调度机制恰好完美契合这一需求。下面总结一下仿真流程:首先进行初始化,包括初始化 CloudSim、创建两个 Datacenter,以及创建第一个 Broker 并提交 VM 和 Cloudlet;接着启动 GlobalBroker,其启动时会自行调度一个延迟 200 的事件;随后仿真开始运行,事件队列不断推进;当仿真时钟达到 200 时,事件触发,GlobalBroker 处理 CREATE_BROKER 事件,创建新的 Broker、VM 和 Cloudlet;之后仿真继续,新 Broker 加入仿真,所有 Cloudlet 持续被调度执行。

CloudSimExample9

CloudSimExample9 主要展示了两种 Cloudlet 调度策略:Time-Shared(时间共享) 和 Space-Shared(空间共享)。Time-Shared(时间共享)指的是同一台 VM 的 CPU 可以被多个 Cloudlet 并发使用,这些 Cloudlet 按照时间片轮转的方式执行,共享 CPU 时间。Space-Shared(空间共享)是指每个 Cloudlet 占用整个 CPU 核心并直至完成才释放,Cloudlet 之间顺序执行,不会并发使用同一个 CPU 核心。

5 Multi Extension

CloudSimMultiExtensionExample1

CloudSimMultiExtensionExample1 的代码展示了如何在同一仿真中同时使用 VM(基于 CloudSim 的虚拟机)和 Container(基于 ContainerCloudSim 的容器)。其中的核心思想是通过 VM(VirtualEntity)承载资源 + Container(GuestEntity)承载 Cloudlet + Cloudlet 绑定 ID,实现 VM 和 Container 混合仿真。传统 CloudSim VM(即 VirtualEntity 或 Vm)用于运行 Cloudlet,而 ContainerCloudSim Container 是基于 CloudSim 的扩展,用于模拟可在 VM 内部运行 Cloudlet 的容器,CloudSimMultiExtensionExample1 目标则是在同一 DataCenter 中混合 VM 和容器,同时提交 Cloudlet,使 VM 和 Container 都能被调度。

在实验中,首先初始化 CloudSim 仿真环境,创建用于提交虚拟机(VM)、容器(Container)和任务(Cloudlet)的 Broker:

CloudSim.init(num_user, calendar, trace_flag);
DatacenterBroker broker = createBroker();

随后建立宿主机列表 hostList,每台 Host 拥有多核 CPU(PE 列表),采用 Space-Shared 类型的 VM 调度器,可同时承载虚拟机与容器:

List<Pe> peList = new ArrayList<>();
peList.add(new Pe(0, new PeProvisionerSimple(mips)));
peList.add(new Pe(0, new PeProvisionerSimple(mips)));
peList.add(new Pe(0, new PeProvisionerSimple(mips)));
peList.add(new Pe(0, new PeProvisionerSimple(mips)));hostList.add(new Host(0, new RamProvisionerSimple(ram), new BwProvisionerSimple(bw), storage, peList, new VmSchedulerSpaceShared(peList)));

接着创建可运行容器的虚拟机对象(VmVirtualEntity),其自身具备 Cloudlet 调度器和 VM 调度器,能够在内部进一步分配资源给 Cloudlet 或容器,并通过 hostList.add(vm1) 将其加入数据中心的资源池:

peList = new ArrayList<>();
peList.add(new Pe(0, new PeProvisionerSimple(mips/4)));
peList.add(new Pe(1, new PeProvisionerSimple(mips/4)));VirtualEntity vm1 = new Vm(1, brokerId, (double) mips/2, pesNumber, ram, bw, size, vmm,new CloudletSchedulerTimeShared(),new VmSchedulerTimeShared(peList),new RamProvisionerSimple(ram),new BwProvisionerSimple(bw),peList);vmlist.add(vm1);
hostList.add(vm1);

之后在 VM 上创建容器对象(GuestEntity),每个容器拥有独立的 Cloudlet 调度器(可为 Time-Shared 或 Space-Shared),由 VM 提供运行所需的计算资源:

GuestEntity container = new Container(3, brokerId, 100, pesNumber, ram/2, bw/2, size/2, "Docker", new CloudletSchedulerTimeShared());
containerlist.add(container);GuestEntity container2 = new Container(4, brokerId, 100, pesNumber, ram/2, bw/2, size/2, "Docker", new CloudletSchedulerSpaceShared());
containerlist.add(container2);

完成资源定义后,创建 Datacenter 管理所有 Host、VM 和容器,并由 Broker 提交这些实体以统一调度:

createDatacenter("Datacenter_0");// submit vm and container list to the broker
broker.submitGuestList(vmlist);
broker.submitGuestList(containerlist);

接着创建 Cloudlet 任务并通过 cloudlet.setGuestId() 绑定到对应的 VM 或容器上,使得任务能够在不同层级的计算实体中同时执行:

Cloudlet cloudlet = new Cloudlet(0, length, pesNumber, fileSize, outputSize, utilizationModel, utilizationModel, utilizationModel);
cloudlet.setUserId(brokerId);
cloudlet.setGuestId(3); // 绑定到 container 3
cloudletList.add(cloudlet);

仿真启动后,Datacenter 根据各层调度器策略分配 CPU、内存与带宽资源,VM 和容器内的 Cloudlet 并行运行,最终输出结果可展示各 Cloudlet 在不同实体上的执行情况:

CloudSim.startSimulation();
CloudSim.stopSimulation();List<Cloudlet> newList = broker.getCloudletReceivedList();
printCloudletList(newList);

CloudSimMultiExtensionExample2

CloudSimMultiExtensionExample2 的代码展示了 如何在 CloudSim 中模拟包含网络拓扑的 DAG 工作流(Tandem DAG)应用,以及 VM/容器在不同主机上的调度对网络使用的影响。其中任务 A 依赖于任务 B 的执行结果。在物理层面,有两台主机(Host0 和 Host1),每台主机上部署若干虚拟机(VM0、VM1、VM2、VM3)和容器(C4)。所有主机通过一个 ToR 交换机互联。通过这种配置,Cloudlet(云任务)可以被分配到不同的 VM 或容器上执行,如果依赖的任务分布在不同主机上,它们之间的数据传输将经过交换机,从而模拟网络延迟和带宽消耗。这种场景能够展示 DAG 任务调度与网络拓扑对任务执行和数据传输的影响。

在实验中,首先初始化 CloudSim 仿真环境,并创建 Broker,用于统一提交虚拟机(VM)、容器(Container)以及任务(Cloudlet):

CloudSim.init(num_user, calendar, trace_flag);
broker = new DatacenterBroker("Broker");

随后使用 NetworkDatacenter(而非普通 Datacenter)作为数据中心类型,使其在管理 Host、VM、容器的同时支持网络通信功能,从而能够模拟更真实的云网络环境:

datacenter = createDatacenter("Datacenter_0");

接着创建宿主机列表,每个 Host 为 NetworkHost 类型,可统计网络带宽占用情况,并在 CreateNetwork() 方法中将其连接到 ToR 交换机,实现主机间的网络互联:

for (int i=0; i<numberOfHosts; i++) {List<Pe> peList = new ArrayList<>();peList.add(new Pe(0, new PeProvisionerSimple(mips)));peList.add(new Pe(1, new PeProvisionerSimple(mips)));hostList.add(new NetworkHost(i, new RamProvisionerSimple(ram),new BwProvisionerSimple(bw), storage, peList, new VmSchedulerTimeShared(peList)));
}

在网络宿主机上创建虚拟机与容器,其中 VM 使用 NetworkVm 类型以模拟虚拟机层面的网络带宽消耗,容器使用 NetworkContainer 类型并绑定到其所在 VM 的 Host。VM 与 Container 均继承自 GuestEntity,因此 Cloudlet 可以直接绑定到任意一层计算实体上执行:

guestList = CreateVMs(datacenter.getId());
GuestEntity container = new NetworkContainer(4, broker.getId(), 100, 1, 1, 1, 1, "Docker", new CloudletSchedulerTimeShared());
container.setVirtualizationOverhead(10);
container.setHost((HostEntity) guestList.get(1));
containerList.add(container);

接下来通过 AppCloudlet 定义一组任务(Cloudlet):

AppCloudlet app = new AppCloudlet(AppCloudlet.APP_Workflow, 0, 2000, broker.getId());
createTaskList(app);

createTaskList() 方法中创建任务 A(cla)和任务 B(clb),分别绑定到容器与虚拟机,并配置执行阶段与数据传输阶段:

cla.addExecutionStage(1000);
cla.addSendStage(1000, clb);
clb.addRecvStage(cla);
clb.addExecutionStage(1000);

以构建具有依赖关系的 DAG(A → B),从而模拟不同任务间的通信过程。然后建立 ToR 交换机,将 Host0 与 Host1 连接到该交换机上,使得当 DAG 中的任务位于不同宿主机时,数据传输会经过交换机并消耗带宽资源:

Switch ToRSwitch = new Switch("Edge0", NetworkConstants.EdgeSwitchPort, Switch.SwitchLevel.EDGE_LEVEL,0, NetworkConstants.BandWidthEdgeHost, NetworkConstants.BandWidthEdgeAgg, dc);dc.registerSwitch(ToRSwitch);// Attach to hosts
for (NetworkHost netHost : dc.<NetworkHost>getHostList()) {dc.attachSwitchToHost(ToRSwitch, netHost);
}

之后将所有 VM、Container 和 Cloudlet 提交给 Broker,由其统一调度执行。在仿真过程中,云任务分别在对应的 VM 或容器中运行,若任务间存在跨 Host 的数据依赖,系统将自动模拟网络传输过程与带宽占用:

broker.submitGuestList(guestList);
broker.submitGuestList(containerList);
broker.submitCloudletList(app.cList);CloudSim.startSimulation();
CloudSim.stopSimulation();

仿真结束后,系统输出每个 Cloudlet 的执行状态、开始与结束时间,并统计总数据传输量,从结果中可直观观察网络通信在任务执行中的作用与影响:

List<Cloudlet> newList = broker.getCloudletReceivedList();
printCloudletList(newList);
System.out.println("numberofcloudlet " + newList.size() + " Data transfered " + datacenter.totalDataTransfer);

CloudSimMultiExtensionPaperExample

CloudSimMultiExtensionPaperExample 的代码展示了 如何在 CloudSim 中模拟带有网络拓扑的周期性串联 DAG 工作流(A → B)应用。该示例可用于分析 任务调度、网络拓扑结构以及虚拟化层级(VM/Container) 对系统性能的影响。实验模拟了一个含有 4 台宿主机(Host0–Host3)、两层交换机(ToR + Aggregation)、以及虚拟机和容器的层次化云数据中心环境。每个周期内都会触发一个由两个任务组成的工作流:任务 A 执行后将结果发送给任务 B(A → B)。若 A 与 B 分布在不同主机上,其数据传输将通过交换机进行,从而引入网络延迟和带宽消耗。首先初始化 CloudSim 仿真器,并创建自定义的 DatacenterBrokerEX。Broker 负责统一管理 VM、容器和任务(Cloudlet)的调度与提交:

CloudSim.init(num_user, calendar, trace_flag);
broker = new DatacenterBrokerEX("Broker", 1000000);

CloudSim.init() 用于初始化核心调度引擎。DatacenterBrokerEX 是一个扩展 Broker,支持多级虚拟化实体(VM + Container)的调度。接着,使用 NetworkDatacenter(网络型数据中心)来支持拓扑与数据传输模拟。每个主机通过带宽受限的交换机互联,从而使任务通信的网络成本可被准确建模。

NetworkDatacenter datacenter = createDatacenter("Datacenter_0");

createDatacenter() 中定义了系统架构(x86、Linux、Xen)、成本模型(CPU、内存、带宽)和自定义的 VM 分配策略(VmAllocationWithSelectionPolicy)。数据中心包含 4 台主机(Host0–Host3),每台主机为 NetworkHost 类型,拥有 2 个处理核心(PE)、大容量 RAM、存储和 10 Gbps 带宽:

for (int i = 0; i < numberOfHosts; i++) {List<Pe> peList = new ArrayList<>();peList.add(new Pe(0, new PeProvisionerSimple(mips)));peList.add(new Pe(1, new PeProvisionerSimple(mips)));hostList.add(new NetworkHost(i,new RamProvisionerSimple(ram),new BwProvisionerSimple(bw),storage,peList,new VmSchedulerTimeShared(peList)));
}

每个 NetworkHost 能统计带宽占用情况。VmSchedulerTimeShared 模拟时间片调度,使多个 VM 可以并行共享主机资源。每台宿主机上部署一个虚拟机(共 4 个),类型为 NetworkVm,可记录虚拟层级的网络流量开销:

for (int i = 0; i < numberOfVms; i++) {gList.add(new NetworkVm(4 + i,broker.getId(),vmMips,1,ram,vmBw,size,"Xen",new CloudletSchedulerTimeShared(),new VmSchedulerTimeShared(peList),new RamProvisionerSimple(ram),new BwProvisionerSimple(vmBw),peList));gList.getLast().setVirtualizationOverhead(vmVirtOverhead);
}

setVirtualizationOverhead() 定义虚拟化额外开销(VM 层面的性能损失)。ID 从 4 开始,以区分于主机编号。容器(NetworkContainer)为第二层虚拟化单元,同样支持网络通信与资源隔离。若启用嵌套虚拟化,可将容器绑定到 VM 上:

for (int i = 0; i < numberOfContainers; i++) {gList.add(new NetworkContainer(8 + i,broker.getId(),contMips,1,ram,contBw,size,"Xen",new CloudletSchedulerTimeShared()));gList.getLast().setVirtualizationOverhead(contVirtOverhead);
}

容器 ID 从 8 开始。可设置 nestedContainers = true,使容器运行在虚拟机内部。每个周期性任务为一个 AppCloudlet,包含两个节点任务 A、B:

AppCloudlet app = new AppCloudlet(AppCloudlet.APP_Workflow, i, deadline, broker.getId());
createTaskList(app);
broker.submitCloudletList(app.cList, distr.sample());

ExponentialDistr 控制任务的周期性触发时间(随机到达)。deadline 表示每个 DAG 的时限要求。在构建 DAG 任务依赖(A → B)时,createTaskList() 定义了任务 A 和 B,并建立依赖关系:

NetworkCloudlet cla = new NetworkCloudlet(...);
cla.addExecutionStage(firstTaskExecLength);
cla.addSendStage(payloadSize, clb);NetworkCloudlet clb = new NetworkCloudlet(...);
clb.addRecvStage(cla);
clb.addExecutionStage(secondTaskExecLength);

A(cla)先执行,然后发送数据给 B(clb)。B 需要先接收数据(addRecvStage)后才能执行。若 A、B 位于不同主机,则数据通过交换机传输,模拟真实网络开销。对于网络拓扑,网络结构完全匹配注释中的拓扑图:

Switch ToRSwitch1 = new Switch("Edge0", ..., EDGE_LEVEL, ..., dc);
Switch ToRSwitch2 = new Switch("Edge1", ..., EDGE_LEVEL, ..., dc);
Switch AggrSwitch = new Switch("Aggr0", ..., AGGR_LEVEL, ..., dc);dc.registerSwitch(ToRSwitch1);
dc.registerSwitch(ToRSwitch2);
dc.registerSwitch(AggrSwitch);dc.attachSwitchToSwitch(ToRSwitch1, AggrSwitch);
dc.attachSwitchToSwitch(ToRSwitch2, AggrSwitch);// 每个 ToR 连接两个 Host
dc.attachSwitchToHost(ToRSwitch1, netHosts.get(0));
dc.attachSwitchToHost(ToRSwitch1, netHosts.get(1));
dc.attachSwitchToHost(ToRSwitch2, netHosts.get(2));
dc.attachSwitchToHost(ToRSwitch2, netHosts.get(3));

最后由 Broker 负责将所有 VM、容器和任务提交到模拟环境中,启动仿真:

broker.submitGuestList(vmList);
broker.submitGuestList(containerList);CloudSim.startSimulation();
CloudSim.stopSimulation();

仿真结束后,输出所有 Cloudlet(任务)的执行详情:

List<Cloudlet> newList = broker.getCloudletReceivedList();
printCloudletList(newList);
System.out.println("numberofcloudlet " + newList.size() + " Data transfered " + datacenter.totalDataTransfer);

同时还生成一个 .csv 文件记录:应用编号、起止时间、makespan、deadline、lateness 等统计信息。

CloudSimMultiExtensionPaperExampleRunner

CloudSimMultiExtensionPaperExampleRunner 是一个实验批量运行器(实验自动化脚本),
用于批量执行 CloudSimMultiExtensionPaperExample 的多种配置场景,比较不同网络拓扑、虚拟化层次与任务调度方式下的性能差异。它的主要功能是:自动组合不同的实验变量(VM/容器分布方式、网络拓扑、负载大小、任务激活次数、虚拟化开销),依次调用 CloudSimMultiExtensionPaperExample.main() 来执行每一组仿真实验。具体考察:首先是 DAG 任务之间的数据依赖传输延迟,这直接关系到任务执行的衔接效率;其次要分析虚拟化层开销带来的作用,涵盖 VM、容器以及多层虚拟化等不同形式的开销对性能的损耗;再者,网络拓扑层次的差异也不容忽视,需探究同主机、同 ToR、跨 Aggregation 等不同网络环境下的性能表现;同时,任务重复执行次数的累积影响,尤其是针对周期性任务,其多次执行产生的性能叠加效应需纳入考量;最后,数据量大小(即 payload size)作为关键变量,对系统整体性能的影响也需进行细致评估。

代码层面,首先,定义三种 基于虚拟机(VM) 的任务布局方式。其中 "cla""clb" 是两个任务(Cloudlet),数字代表它们运行的虚拟机编号。编号相同表示任务在同一主机上,不同表示分布在不同主机:

// i) 同一主机(任务A和B共用一台VM)——本地通信,无网络消耗
private static Map<String, Integer> getClConfigV_I() {return Map.of("cla", 4, "clb", 4);
}// ii) 同一机架,不同主机——经过 ToR 交换机通信
private static Map<String, Integer> getClConfigV_II() {return Map.of("cla", 4, "clb", 5);
}// iii) 不同机架——需经过聚合交换机通信
private static Map<String, Integer> getClConfigV_III() {return Map.of("cla", 4, "clb", 6);
}

接着,定义三种 基于容器(Container) 的布局方式,逻辑与上面一致,只是容器编号不同:

// i) 同一VM中的容器
private static Map<String, Integer> getClConfigC_I() {return Map.of("cla", 8, "clb", 8);
}// ii) 同一机架不同VM
private static Map<String, Integer> getClConfigC_II() {return Map.of("cla", 8, "clb", 9);
}// iii) 不同机架上的容器
private static Map<String, Integer> getClConfigC_III() {return Map.of("cla", 8, "clb", 10);
}

然后进入 main() 主函数,先关闭 CloudSim 的日志输出,以免大量打印干扰实验结果:

public static void main(String[] args) {String[] emptyArgs = new String[0];Log.setDisabled(true);

设置虚拟化层的性能开销参数,VM 的虚拟化损耗为 5,容器的损耗为 3。这些值会在仿真中体现为计算延迟或资源利用率下降:

CloudSimMultiExtensionPaperExample.vmVirtOverhead = 5;
CloudSimMultiExtensionPaperExample.contVirtOverhead = 3;

创建一个配置表 configs,里面保存不同实验场景的任务布局方案。键(key)代表场景名称(如 “V-I”、“C-II”),值(value)是对应的任务→运行节点映射表:

Map<String, Map<String, Integer>> configs = new HashMap<>();
configs.put("V-I", getClConfigV_I());
configs.put("V-II", getClConfigV_II());
configs.put("V-III", getClConfigV_III());
configs.put("C-I", getClConfigC_I());
configs.put("C-II", getClConfigC_II());
configs.put("C-III", getClConfigC_III());
configs.put("N-I", getClConfigC_I());
configs.put("N-II", getClConfigC_II());
configs.put("N-III", getClConfigC_III());

接下来定义两种负载大小(payload): 一个小(1000字节),一个大(10亿字节)。这些值代表任务之间传输的数据量大小:

Map<String, Integer> payloads = new HashMap<>();
payloads.put("small-payload", 1000);
payloads.put("big-payload", 1000000000);

再定义任务激活次数(activations)。如果为 1,表示只运行一次;如果为 20,表示周期性重复执行 20 次:

List<Integer> activations = new ArrayList<>();
activations.add(1);
activations.add(20);

这里生成一个字符串标记当前实验是否包含虚拟化开销(VO 表示开启虚拟化)。方便在保存结果文件时区分不同实验条件:

String voString = (CloudSimMultiExtensionPaperExample.vmVirtOverhead + CloudSimMultiExtensionPaperExample.contVirtOverhead > 0)? "VO" : "none";

主循环开始。外层循环控制激活次数(单次或多次),中层循环遍历所有配置场景,内层循环测试不同数据量:

for (int activation : activations) {CloudSimMultiExtensionPaperExample.numberOfPeriodicActivations = activation;String actString = (activation > 1) ? "many" : "single";for (var config : configs.entrySet()) {CloudSimMultiExtensionPaperExample.cloudletToGuest = config.getValue();

根据场景名称判断是使用虚拟机、容器还是嵌套容器。通过修改全局变量来控制实验环境。

CloudSimMultiExtensionPaperExample.numberOfContainers = (config.getKey().indexOf('V') >= 0) ? 0 : 4;
CloudSimMultiExtensionPaperExample.numberOfVms = (config.getKey().indexOf('C') >= 0) ? 0 : 4;
CloudSimMultiExtensionPaperExample.nestedContainers = config.getKey().indexOf('N') >= 0;

然后遍历不同数据量,在每种条件下打印当前实验信息并启动仿真:

for (var p : payloads.entrySet()) {System.out.println("Running '" + actString + "' example with payload "+ p.getValue() + " and config " + config.getKey());CloudSimMultiExtensionPaperExample.payloadSize = p.getValue();CloudSimMultiExtensionPaperExample.fileInfo = "-"+ p.getKey() + "-" + config.getKey() + "-" + actString + "-" + voString;CloudSimMultiExtensionPaperExample.main(emptyArgs);System.out.println();
}

DiamondAppMultiExtensionExample

DiamondAppMultiExtensionExample 模拟的是一个有向无环图(DAG)型任务依赖结构,如下图所示:该结构代表了四个任务(A、B、C、D)之间的依赖关系,具体表现为:A 是起点任务,不存在前置依赖任务;当 A 执行完成后,其产生的结果会同时传递给 B 和 C,作为 B 和 C 执行的基础;只有当 B 和 C 都顺利执行完毕后,二者的结果才会进一步传递给 D,供 D 进行后续处理;最终,D 作为整个工作流(Workflow)的终点任务,完成全部流程。而 CloudSim 正是利用这种 DAG 结构来清晰地表示任务之间的数据依赖关系与具体的执行顺序。

createTaskList() 方法中,首先为四个任务 A、B、C、D 创建对应的 NetworkCloudlet 对象。每个任务都分配给不同的虚拟机(或容器),并登记到应用的任务列表中:

NetworkCloudlet cla = new NetworkCloudlet(...);
cla.setUserId(broker.getId());
cla.setGuestId(guestList.get(0).getId());
appCloudlet.cList.add(cla);NetworkCloudlet clb = new NetworkCloudlet(...);
clb.setUserId(broker.getId());
clb.setGuestId(guestList.get(1).getId());
appCloudlet.cList.add(clb);// 同理创建 C、D 两个任务

这样,我们便建立了四个独立的计算任务实体。接下来定义它们之间的数据依赖关系,以形成 “菱形” 的执行结构。任务 A 是整个工作流的起点。 它先执行一定时间的计算(addExecutionStage(1000)), 然后将结果分别发送给任务 B 和任务 C:

cla.addExecutionStage(1000);
cla.addSendStage(1000, clb);
cla.addSendStage(1000, clc);

这两条发送操作意味着:A 的输出会并行流向 B、C,于是形成了依赖边 A → B 与 A → C。A 本身没有输入,因此是 DAG 的源节点。接着定义 任务 B。它首先等待来自 A 的数据(addRecvStage(cla)),然后执行自身逻辑 1000 时间单位,最后把结果发给任务 D:

clb.addRecvStage(cla);
clb.addExecutionStage(1000);
clb.addSendStage(1000, cld);

这样 B 就形成了依赖链 A → B → D。B 的输出流向 D,成为菱形上方的一条路径。同样地,任务 C 也从 A 接收输入:

clc.addRecvStage(cla);
clc.addExecutionStage(2000);
clc.addSendStage(1000, cld);

不同的是,C 的执行时间更长(2000 时间单位),因此在模拟中会表现出“并行但耗时不同”的特性。C 的输出同样发送给 D,形成另一条路径 A → C → D,即菱形的下半部分。最后定义 任务 D,它是收尾节点。D 要等到 B 和 C 的输出都到达后才能开始执行:

cld.addRecvStage(clb);
cld.addRecvStage(clc);
cld.addExecutionStage(1000);

addRecvStage() 的两次调用建立了双输入依赖。D 的执行代表数据在两条路径汇合后的整合阶段。因此整个 DAG 的拓扑关系为:

     B/ \A   D\ /C

综上,createTaskList() 方法通过依次调用 addExecutionStage()addSendStage()addRecvStage() 三类操作,在 CloudSim 的网络模型中显式地描述了任务间的依赖关系,从而实现了一个典型的“菱形(diamond-shaped)”工作流结构。

TestScheduledResource

TestScheduledResource 是一个CloudSim 框架底层事件调度机制的演示程序。它不模拟虚拟机、任务或数据中心,而是测试 CloudSim 的事件调度系统(SimEvent)和资源队列(ScheduledResource)是如何工作的。程序中,首先定义了三个关键对象:一个“调度资源” res(类型为 ScheduledResource),一个事件发送者 src,和一个事件接收者 dst

static ScheduledResource res;
static SrcEntity src;
static DstEntity dst;

这里的 ScheduledResource 可以理解为一个“带延迟队列的事件调度器”,它允许我们把事件安排在未来某个时间自动触发。首先,是对 CloudSim 初始化与实体注册。程序在 main() 中初始化 CloudSim 仿真环境:

CloudSim.init(num_user, calendar, trace_flag);
res = new ScheduledResource("res", 1.0);
src = new SrcEntity("src");
dst = new DstEntity("dst");

此时模拟环境包含三个实体:一个调度器、一个发送者、一个接收者。接着,主程序向 src 发送了三条定时事件:

CloudSim.send(0, src.getId(), 0.0, CloudActionTags.BLANK, null);
CloudSim.send(0, src.getId(), 10.0, CloudActionTags.BLANK, null);
CloudSim.send(0, src.getId(), 20.0, CloudActionTags.BLANK, null);

每当 src 收到事件时,它会调用 processEvent() 方法:

public void processEvent(SimEvent ev) {Log.printlnConcat(CloudSim.clock(), ": ", getName(), " processEvent()");res.enqueue(SimEvent.SEND, dst.getId(), 100.0, CloudActionTags.BLANK, null);res.enqueueDelay(1000.0, SimEvent.SEND, dst.getId(), 100.0, CloudActionTags.BLANK, null);
}

换句话说:每当 src 被触发一次,它都会安排两条未来的传输任务去执行,模拟“立即发送一次 + 延迟发送一次”。接收者实体dst 实体的 processEvent() 非常简单:

public void processEvent(SimEvent ev) {Log.printlnConcat(CloudSim.clock(), ": ", getName(), " processEvent()");
}

每当 CloudSim 调度系统触发它时,它会输出当前时刻,说明这个事件(由 ScheduledResource 安排的传输)已经到达。主程序启动 CloudSim 的事件循环:

CloudSim.startSimulation();
CloudSim.stopSimulation();

此时,整个仿真时间轴会依次出现:

  1. t=0 时刻:src 第一次被触发 → 安排两条发送
  2. t=10 时刻:src 第二次被触发 → 再安排两条发送
  3. t=20 时刻:src 第三次被触发 → 再安排两条发送
  4. 随着时间推进,dst 会在 t=100t=1100t=120t=1120 等时刻陆续接收到这些事件。

这就是 CloudSim 模拟网络延迟和资源调度的基础机制。在更复杂的例子(如 VM 迁移、任务传输)中,CloudSim 也是用类似的事件队列机制来实现数据流的。

6 总结

通过对 CloudSim 官方15个示例的详细学习,我们可以清晰地掌握这一云计算仿真平台的核心使用方法和进阶功能。以下是对整个学习过程的总结:

6.1 学习路径回顾

从简单到复杂的学习路径体现了 CloudSim 的强大功能和灵活性:

  • 基础入门(示例1-5):从最简单的单数据中心、单主机、单任务开始,逐步增加资源复杂度,掌握核心组件的使用方法和基本仿真流程。
  • 进阶功能(示例6-9):学习可扩展仿真、动态实体创建、暂停恢复机制以及不同调度策略,深入理解 CloudSim 的事件驱动机制。
  • 高级扩展(示例10-15):探索容器虚拟化、网络拓扑、工作流调度和批量实验等高级功能,展现 CloudSim 在复杂云环境模拟中的强大能力。

6.2 核心架构与关键概念

CloudSim 的核心架构围绕几个关键实体构建,形成了清晰的层次结构:

  • 资源层:Host(物理主机)→ VM(虚拟机)→ Container(容器)
  • 任务层:Cloudlet(云任务)→ AppCloudlet(应用工作流)
  • 管理层:Datacenter(数据中心)→ Broker(调度代理)

关键概念包括:

  • 调度策略:Time-Shared vs Space-Shared,影响资源分配方式
  • 事件机制:基于 SimEvent 的离散事件驱动仿真
  • 资源分配:通过 Provisioner 和 Scheduler 实现多级资源管理
  • 网络拓扑:支持交换机层次结构,模拟真实数据中心网络

6.3 重要技术要点

  1. 基本流程记忆法:“CDBVC” - CloudSim初始化、Datacenter创建、Broker创建、Vm创建、Cloudlet创建
  2. 调度器选择:
    • VmScheduler:管理VM间的主机资源分配
    • CloudletScheduler:管理Cloudlet间的VM资源分配
    • 时间共享 vs 空间共享策略对性能有显著影响
  3. 多用户环境:通过多个Broker模拟不同用户,体现资源竞争和隔离机制
  4. 动态仿真:支持运行时暂停、恢复和实体创建,适应复杂仿真需求
  5. 混合虚拟化:VM与容器在同一环境中协同工作,模拟现代云基础设施

通过这15个示例的系统学习,我们不仅掌握了 CloudSim 的使用方法,更重要的是建立了对云计算系统运行机制的深入理解。这种理解对于从事云计算相关的研究、开发和运维工作都具有重要价值。CloudSim 作为一个强大的研究工具,将继续在云计算技术的发展中发挥重要作用。

http://www.dtcms.com/a/545631.html

相关文章:

  • 会外语和做网站制作微信网站模板免费下载
  • 优秀shell脚本搜集——筑梦之路
  • uniapp 实现一个底部悬浮面板
  • 中国桥梁空间分布数据
  • MutableStateFlow、StateFlow、LiveData在Compose中的运用
  • 网站建设的总结与评价专业定制网站开发公司
  • 应对AI全球化部署挑战:南凌科技云连接服务实现算法模型全球稳定传输
  • 公司网站建设岗位手机软件定制开发公司
  • 网站推广app软件一级注册工程师
  • LeetCode算法日记 - Day 87: 单词拆分
  • 学术论文写作与发表精讲:融合AI工具的高效方法与实战案例
  • 天津开发网站公司虚拟主机如何建设多个网站
  • 跟公司产品做网站制作app软件工具免费
  • 133-Spring AI Alibaba Vector Redis 功能完整案例
  • 线段树详解
  • AI 大模型应用中的图像,视频,音频的处理
  • 2025年大专建筑工程技术专业前景!
  • @1Panel 全面指南:从部署到高阶使用
  • SAP MM 采购申请转采购订单功能分享
  • FPGA设计中的“幽灵信号:一条走线,两种命运——浅析路径延迟导致的逻辑错误
  • 网站建设将新建用户授权为管理员免费搭建手机网站源码
  • 北京企业网站建设费用新闻最新消息
  • 算法工具箱之二分查找
  • undefined reference to `cJSON_AddStringToObject‘
  • 仓颉语言中TreeMap红黑树结构的实现与优化
  • Rust 的构建系统和包管理器
  • AI驱动嵌入式软件全链路变革:从芯片到系统的深度智能重构
  • 怎么修改网站域名推广网站排行榜
  • 靠谱的电磁阀维护保养
  • 【自动化测试函数 (下)】Web自动化攻坚:应对加载等待、浏览器导航与无头模式的自动化脚本艺术