Το Cloudsim είναι ένα framework προσομοίωσης, γραμμένο σε Java, το οποίο επιτρέπει στον χρήστη να ελέγχει κάθε οπτική ενός Cloud περιβάλλοντος (είτε τον αλγόριθμό του, ή την πλατφόρμα του, ή την αρχιτεκτονική του). Με το Cloudsim, ο χρήστης μπορεί να επιβεβαιώσει στρατηγικές στην υπολογιστική νέφους, να προσομοιώσει ένα δικό του cloud περιβάλλον και να χτίσει δικές του λύσεις. Εφόσον είναι προσομοιωτής, δεν μπορεί να τρέξει πραγματική εφαρμογή, να τρέξει μόνο του ή να αντικαταστήσει ένα cloud περιβάλλον.
Note
|
Εντολή για να τρέξει από το terminal |
#!/bin/bash
java -classpath jars/cloudsim-4.0.jar:jars/cloudsim-examples-4.0.jar org.cloudbus.cloudsim.examples.CloudSimExample${1}
Στο CloudExample6, δημιουργούνται 2 datacenters με 2 hosts το καθένα. Μέσα στη main φτιάχνει τα δύο datacenters, ενώ μέσα στη μέθοδο createDatacenter παρατηρείτε ότι έχει δύο hosts το καθένα. Για το κάθε datacenter, οι hosts έχουν μερικά χαρακτηριστικά. Ο host 0, είτε αυτός είναι μέσα στο πρώτο datacenter ή στο δεύτερο, έχει 4 επεξεργαστές, ενώ ο host 1 έχει 2, με τα υπόλοιπα χαρακτηριστικά τους να είναι ίδια. Δηλαδή έχουν 2048 MB κύριας μνήμης (RAM), 10 MB δευτερεύουσας μνήμης (storage), 10 KB εύρος ζώνης (bandwidth) και χρησιμοποιούν έναν συγχρονιστή χρόνου που επιτρέπει το host να έχει παραπάνω από ένα επεξεργαστή.
Αφού φτιάξει τα παραπάνω, μπορούν να . Αναλυτικά, ότι είναι x86 αρχιτεκτονικής, ότι τρέχει Linux, ότι ο παρακολουθητής των εικονικών μηχανών (virtual machine monitor) είναι ο xen, ότι βρίσκεται στο δέκατο timezone, το κόστος χρησιμοποιώντας αυτή την υπηρεσία είναι 3, η μνήμη 0.05 και της μνήμης 0.1.
Στη συνέχεια, επιστρέφοντας στην main του προγράμματος, δημιουργεί έναν broker, ο οποίος είναι υπεύθυνος για την διαχείριση των VM. Επιπρόσθετα, αρχίζει να φτιάχνει τις εικονικές μηχανές (Virtual Machines, VM), 20 στο σύνολο. Κάθε VM έχει κάποια συγκεκριμένα χαρακτηριστικά. Έχει ένα μέγεθος των 100 KB, ενώ ζητάει να του παραχωρηθεί 512 MB κύριας μνήμης για να μπορεί να τρέξει. Επίσης μπορεί να εξυπηρέτησει μέχρι 1000 εντολές το δευτερόλεπτα (mips), το εύρος ζώνης είναι επίσης 1000 και έχει έναν επεξεργαστή, με τον monitor να είναι ο Xen. Ο αλγόριθμος που χρησιμοποιείται για να γίνει η προσπάθεια ανάθεσης σε κάποιον host είναι ο CloudletSchedulerTimeShared, οπού προσδιορίζει πόσο χρόνο θα έχει το κάθε cloudlet για να χρησιμοποιήσει τους πόρους. Το cloudlet είναι μία βελτιωμένη έκδοση του σημερινού cloud συστήματος. Είναι υπεύθυνο για την ανάθεση των VMs στα host.
Τελικά θα φτιαχτούν 6 VMs για το Datacenter 1 και άλλα 6 για το αλλό. Αυτό επειδή ο host 0 του Datacenter 1 έχει τέσσερις πυρήνες και ο host 1 δύο, όποτε 6 πυρήνες στο σύνολο και το κάθε VM ζητάει έναν τουλάχιστον πυρήνα. Επίσης, βλέπουμε ότι κάθε Host χωράει το μέγιστο 4 VMs, αφού το κάθε VM διαχειρίζεται 512 ΜB ram, δηλαδή το 1/4 της συνολικής ram του host (2048 MB). Ακολουθεί πίνακας για τον αριθμό VM ανά host.
Virtual Machine |
Host |
Datacenter |
0, 1, 2, 4 |
0 |
1 |
3, 5 |
1 |
1 |
6, 7, 8, 10 |
0 |
2 |
9, 10 |
1 |
2 |
Note
|
Αυτός ο πίνακας αλλάζει αναλόγως με ποιον αλγόριθμο έχει επιλεχθεί για να κάνει την αντιστοίχηση. |
Μετά τη δημιουργία των VM, αρχίζει να δημιουργεί τα cloudlets, 40 στο σύνολο. Τα χαρακτηριστικά τους είναι: μέγεθος 1000, μέγεθος συστήματος 300, μέγεθος output 300 και μονοπύρηνο. Τέλος, χρησιμοποιεί το UtilizationModel για να μπορεί να παρέχει έναν καλό έλεγχο των πόρων και δίνει ιδιοκτηκότητα στον broker.
Για την αντιστοίχιση cloudlet/vm, ο broker στέλνει ένα-ένα cloudlet σε όλα τα VM. Αφού υπάρχουν 40 cloudlet να αντιστοιχιστούν και 12 VM, σημαίνει ότι το κάθε VM θα έχει 3 cloudlet, με τέσσερα περισσευούμενα, τα οποία θα τα αντιστοιχήσει στα πρώτα 4 VM.
Τέλος, να παρατηρηθεί στα τελικά απότελεσματα ότι οι στήλες επιστρέφουν τις εξής πληροφορίες: το ID του Cloudlet, το Status του, το ID του Datacenter που ανήκει το VM που φιλοξενεί το Cloudlet, το ID του VM, ο χρόνος που πήρε για να τρέξει το simulation, η αρχική ώρα και η τελική ώρα. Καταρχάς όλα τέλειωσαν με τη σειρά που μπήκαν. Κάθε cloudlet πήρε 1 δευτερόλεπτο να τρέξει και να ολοκληρώση την λειτουργία του.
Εφόσον εκτελέστηκε αρχικά με time-sharing, θα τροποποιηθεί ο κώδικας κατάλληλα για να τρέχει με space sharing. Έγιναν οι εξής αλλαγές:
hostList.add(
new Host(
hostId,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList1,
new VmSchedulerSpaceShared(peList1)
)
); // This is our first machine
hostId++;
hostList.add(
new Host(
hostId,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList2,
new VmSchedulerSpaceShared(peList2)
)
); // Second machine
vm[i] = new Vm(i, userId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerSpaceShared());
Το πρώτο πράγμα που μπορεί να παρατηρηθεί είναι ότι παρόλο που έχει αλλάξει η στρατηγική πίσω από την δρομολόγηση των VM στους hosts, δεν άλλαξε. Δεν έχει σημασία ο χώρος επειδή είναι υπεραρκετός. Αντιθέτως, η δρομολόγηση των Cloudlets στα VM έχει τροποποιήθει. Δηλαδή πρώτα γεμίζουν όπως μπαίνουν. Δηλαδή ο αλγόριθμος είναι FIFO (First in First out), ενώ στο προηγούμενο δεν είχε σημασία το πως έμπαιναν στη λίστα αναμονής, έβγαιναν μόνο όποτε "γέμιζε" ένα vm. Με άλλα λόγια όποτε φόρτωνε όλα τα Cloudlets.
Επόμενο βήμα είναι το simulator να τρέχει όλα τα VM. Υπάρχουν δύο τρόποι που θα μπορούσε να τροποποιήθει: είτε να δώθει παραπάνω ram στον host, είτε να αυξήθουν τα cores των host. Αρχικά ας αυξηθεί η ram. Προς το παρόν, οι host έχουν 2048 ΜΒ. Εφτά VM δεν μπορούν να τρέξουν προς το παρόν. Χρειάζεται 3584 MB παραπάνω ram συνολικά για να τρέξουν. Πρέπει να προστεθούν τουλάχιστον 1792 MB ram ανά host, φέρνοντας την τελική ram ανά host στα 3840 MB ram. Επιπρόσθετα, να παρατηρηθεί ότι κάθε CPU μπορεί να δεχθεί 1000 instructions το δευτερόλεπτο, όσες και το κάθε VM. Μαθηματικά, περισσεύουν 6 VM, δηλαδή 6000 MIPS. Εφόσον αυτό ισχύει, θα πρέπει να αυξηθούν και τα MIPS στα 2000 σε 4 τυχαίους CPUs, για να μπορεί ο κάθε επεξεργαστής να επεξεργαστεί παραπάνω VMs. Αυτό έχει ως αποτέλεσμα να μπορεί να εξυπηρετήσει τα περισσευούμενα VM που δε μπορούσε πριν.
Βεβαία, πρώτα θα φορτώσει τα πρώτα 12 όπως και πριν, και με το που αδειάσει κάποια θέση, θα μπει στην άδεια θέση του το νέο VM. Για να λυθεί αυτό το πρόβλημα θα πρέπει να αυξηθεί ο αριθμός των cores, δηλαδή 2 CPUs παραπάνω ανά host.
List<Pe> peList1 = new ArrayList<Pe>();
int mips1 = 2000;
int mips2 = 1000;
// 3. Create PEs and add these into the list.
//for a quad-core machine, a list of 4 PEs is required:
peList1.add(new Pe(0, new PeProvisionerSimple(mips1)));
// need to store Pe id and MIPS Rating
peList1.add(new Pe(1, new PeProvisionerSimple(mips1)));
peList1.add(new Pe(2, new PeProvisionerSimple(mips1)));
peList1.add(new Pe(3, new PeProvisionerSimple(mips2)));
peList1.add(new Pe(4, new PeProvisionerSimple(mips1)));
peList1.add(new Pe(5, new PeProvisionerSimple(mips1)));
//Another list, for a dual-core machine
List<Pe> peList2 = new ArrayList<Pe>();
peList2.add(new Pe(0, new PeProvisionerSimple(mips1)));
peList2.add(new Pe(1, new PeProvisionerSimple(mips2)));
peList2.add(new Pe(2, new PeProvisionerSimple(mips2)));
peList2.add(new Pe(3, new PeProvisionerSimple(mips2)));
Στα αποτελέσματα, αρχικά χωρίς τους έξτρα επεξεργαστές, δε παρατηρείτε μεγάλη διαφορά στην εκτέλεση. Ακόμα, κάθε VM έχει διάρκεια 1 δευτερόλεπτο. Παρομοίως και στους έξτρα επεξεργαστές. Η διαφορά, βέβαια, είναι στο τελικό χρόνο. Αντί να τελειώσει στα 3.2 δευτερόλεπτα, είναι 1 δευτερόλεπτο πιο γρήγορο και τελειώνει στα 2.2 δευτερόλεπτα.
Για να αλλάξει η στρατηγική που ακολουθάει το simulator στον κώδικα για την αντιστοίχιση VMs σε hosts και Cloudlets σε VMs θα πρέπει να γίνουν οι εξής αλλαγές στα εξής σημεία του κώδικα.
hostList.add(
new Host(
hostId,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList1,
new VmSchedulerTimeShared(peList1)
)
); // This is our first machine
hostId++;
hostList.add(
new Host(
hostId,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList2,
new VmSchedulerTimeShared(peList2)
)
); // Second machine
vm[i] = new Vm(i, userId, mips, pesNumber, ram, bw, size, vmm, new CloudletSchedulerTimeShared());
Μπορεί κανείς να διαλέξει διάφορες άλλες τεχνικές, όπως το VmScheduleSpaceShared. Κοιτάζοντας τον κώδικα και το documentation του στο διαδίκτυο παρατηρείτε μια πληθώρα από διαφορετικές στρατηγικές. Για παράδειγμα, μια εναλλακτική στρατηγική είναι το VmSchedulerTimeSharedBySubscription για την αντιστοίχιση VM σε Hosts, όπου φορτώνει όσα πιο πολλά cloudlets χωράει εκείνη τη στιγμή και όταν «γεμίσει», βάζει τα υπόλοιπα σε μία λίστα αναμονής. Για την αντιστοίχιση Cloudlets σε VM, από το CloudletSchedulerDynamicWorkload, όπου θεωρητικά δουλεύει με time-shared, με τη διαφορά ότι υποθέτει πως τουλάχιστον 1 Cloudlet είναι μία δικτυακή υπηρεσία.
Για να τροποποιηθεί το μοντέλο για την αντιστοίχιση VM και Cloudlets, θα αλλάξει το από κάτω αντικείμενο.
UtilizationModel utilizationModel = new UtilizationModelFull();
Υπάρχουν διάφορα, πρώτα ας αναλυθεί το UtilizationModelNull. Καταρχάς, το Cloudlet πάντα ζητάει μηδενική χωρητικότητα. Στα αποτελέσματα, να παρατηρηθεί ότι η διάρκεια που λειτουργεί κάθε Cloudlet έχει αυξηθεί κατά 1 δευτερόλεπτο. Δηλαδή, παίρνει 2 δευτερόλεπτα. Υπάρχει επίσης το UtilizationModelStohastic όπου το κάθε Cloudlet παίρνει μία τυχαία τιμή κάθε πλαίσιο.
Το custom παράδειγμα είναι ένας συνδιασμός του έκτου παραδείγματος με του όγδοου. Έχει δωθεί SpaceShared για τον scheduler των Cloudset, ενώ για την αντιστοίχηση των hosts με τα VM έχει δωθεί TimeShared. Έτσι, κληρωνομεί τα πλεοκεκτήματα του TimeShared (δηλαδή να χωρίζει και να δουλεύει παρόμοια με το RoundRobin), ενώ παράλληλα έχει μια πιο κατανεμημένη οργάνωση στην αντιστοίχηση των Cloudlet με τα VM.
package org.cloudbus.cloudsim.examples;
import org.cloudbus.cloudsim.*;
import org.cloudbus.cloudsim.core.CloudSim;
import org.cloudbus.cloudsim.provisioners.BwProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.RamProvisionerSimple;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
public class CustomCloudSimExample {
/**
* The cloudlet list.
*/
private static List<Cloudlet> cloudletList;
/**
* The vmlist.
*/
private static List<Vm> vmlist;
private static List<Vm> createVM(int userId, int vms, int idShift) {
//Creates a container to store VMs. This list is passed to the broker later
var list = new LinkedList<Vm>();
//VM Parameters
var size = 300; //image size (MB)
int ram = 500; //vm memory (MB)
int mips = 500;
var bw = 1000;
int pesNumber = 1; //number of cpus
var vmm = "Xen"; //VMM name
//create VMs
var vm = new Vm[vms];
for (int i = 0; i < vms; i++) {
vm[i] = new Vm(idShift + i, userId, mips, pesNumber, ram, bw,
size, vmm, new CloudletSchedulerSpaceShared());
list.add(vm[i]);
}
return list;
}
private static List<Cloudlet> createCloudlet(int userId, int cloudlets, int idShift) {
// Creates a container to store Cloudlets
var list = new LinkedList<Cloudlet>();
//cloudlet parameters
var length = 1000;
var fileSize = 300;
var outputSize = 300;
int pesNumber = 1;
var utilizationModel = new UtilizationModelFull();
var cloudlet = new Cloudlet[cloudlets];
for (int i = 0; i < cloudlets; i++) {
cloudlet[i] = new Cloudlet(idShift + i, length, pesNumber, fileSize, outputSize, utilizationModel,
utilizationModel, utilizationModel);
cloudlet[i].setUserId(userId);
list.add(cloudlet[i]);
}
return list;
}
public static void main(String[] args) {
Log.printLine("Starting CustomCloudSimExample...");
try {
// First step: Initialize the CloudSim package. It should be called
// before creating any entities.
var num_user = 2; // number of grid users
var calendar = Calendar.getInstance();
var trace_flag = false; // mean trace events
// Initialize the CloudSim library
CloudSim.init(num_user, calendar, trace_flag);
var globalBroker = new CloudSimExample8.GlobalBroker("GlobalBroker");
// Second step: Create Datacenters
//Datacenters are the resource providers in CloudSim. We need at list one of them to run a CloudSim simulation
@SuppressWarnings("unused")
var datacenter0 = createDatacenter("Datacenter_0");
@SuppressWarnings("unused")
var datacenter1 = createDatacenter("Datacenter_1");
//Third step: Create Broker
var broker = createBroker("Broker0");
assert broker != null;
int brokerId = broker.getId();
//Fourth step: Create VMs and Cloudlets and send them to broker
vmlist = createVM(brokerId, 4, 0); //creating 4 vms
cloudletList = createCloudlet(brokerId, 10, 0); // creating 10 cloudlets
broker.submitVmList(vmlist);
broker.submitCloudletList(cloudletList);
CloudSim.startSimulation();
var newList = broker.getCloudletReceivedList();
newList.addAll(globalBroker.getBroker().getCloudletReceivedList());
CloudSim.stopSimulation();
printCloudletList(newList);
Log.printLine("CustomCloudSimExample finished!");
} catch (Exception e) {
e.printStackTrace();
Log.printLine("The simulation has been terminated due to an unexpected error");
}
}
private static Datacenter createDatacenter(String name) {
var hostList = new ArrayList<Host>();
var peList1 = new ArrayList<Pe>();
int mips = 1000;
peList1.add(new Pe(0, new PeProvisionerSimple(mips)));
peList1.add(new Pe(1, new PeProvisionerSimple(mips)));
int hostId = 0;
int ram = 500; //host memory (MB)
var storage = 1000000; //host storage
int bw = 10000;
hostList.add(
new Host(
hostId++,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList1,
new VmSchedulerTimeShared(peList1)
)
);
hostList.add(
new Host(
hostId,
new RamProvisionerSimple(ram),
new BwProvisionerSimple(bw),
storage,
peList1,
new VmSchedulerSpaceShared(peList1)
)
);
var arch = "x86"; // system architecture
var os = "Linux"; // operating system
var vmm = "Xen";
var time_zone = 10.0; // time zone this resource located
var cost = 3.0; // the cost of using processing in this resource
var costPerMem = 0.05; // the cost of using memory in this resource
var costPerStorage = 0.1; // the cost of using storage in this resource
var costPerBw = 0.1; // the cost of using bw in this resource
var storageList = new LinkedList<Storage>(); //we are not adding SAN devices by now
var characteristics = new DatacenterCharacteristics(
arch, os, vmm, hostList, time_zone, cost, costPerMem, costPerStorage, costPerBw);
Datacenter datacenter = null;
try {
datacenter = new Datacenter(name, characteristics,
new VmAllocationPolicySimple(hostList), storageList, 0);
} catch (Exception e) {
e.printStackTrace();
}
return datacenter;
}
private static DatacenterBroker createBroker(String name) {
DatacenterBroker broker = null;
try {
broker = new DatacenterBroker(name);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return broker;
}
private static void printCloudletList(List<Cloudlet> list) {
Cloudlet cloudlet;
var indent = " ";
Log.printLine();
Log.printLine("========== OUTPUT ==========");
Log.printLine("Cloudlet ID" + indent + "STATUS" + indent +
"Data center ID" + indent + "VM ID" + indent + indent + "Time" + indent +
"Start Time" + indent + "Finish Time");
var dft = new DecimalFormat("###.##");
for (var value : list) {
cloudlet = value;
Log.print(indent + cloudlet.getCloudletId() + indent + indent);
if (cloudlet.getStatus() == Cloudlet.SUCCESS) {
Log.print("SUCCESS");
Log.printLine(indent + indent + cloudlet.getResourceId() + indent + indent +
indent + cloudlet.getVmId() + indent + indent + indent +
dft.format(cloudlet.getActualCPUTime()) + indent + indent +
dft.format(cloudlet.getExecStartTime()) + indent + indent + indent +
dft.format(cloudlet.getFinishTime()));
}
}
}
}