高效分配下一个可用的虚拟机的方法

14
<代码>getNextAvailableVm()方法以循环方式分配特定数据中心的虚拟机。 (该方法返回的整数是所分配的机器)
在数据中心中可能有具有不同配置集的虚拟机。例如:
5 VMs with 1024 memory
4 VMs with 512 memory

Total : 9 VMs

对于这个数据中心,具有1024内存的机器将获得任务比具有512内存的机器多2倍。

因此,该数据中心的机器以以下方式由getNextAvailableVm()返回:

0 0 1 1 2 2 3 3 4 4 5 6 7 8

这是目前的方式,机器正在被归还。但有一个问题。

有时会出现特定机器正在忙碌,无法分配任务的情况。此时应分配下一个可用内存最大的机器来执行任务。我还未能实现这一点。

例如:

0 (allotted first time)
0 (to be allotted the second time)
but if 0 is busy..
allot 1 if 1 is not busy
next circle check if 0 is busy
if not busy allot 0  (only when machine numbered 0 has not handled the requests it is entitled to handle)
if busy, allot the next

以下类中的cloudSimEventFired方法在机器被释放或分配时调用。

    public class TempAlgo extends VmLoadBalancer implements CloudSimEventListener {

    /**
     * Key : Name of the data center
     * Value : List of objects of class 'VmAllocationUIElement'.
     */
    private  Map<String,LinkedList<DepConfAttr>> confMap = new HashMap<String,LinkedList<DepConfAttr>>();
    private Iterator<Integer> availableVms = null;
    private DatacenterController dcc;
    private boolean sorted = false;
    private int currentVM;
    private boolean calledOnce = false;
    private boolean indexChanged = false;
    private LinkedList<Integer> busyList = new LinkedList<Integer>();

    private Map<String,LinkedList<AlgoAttr>> algoMap = new HashMap<String, LinkedList<AlgoAttr>>();
    private Map<String,AlgoHelper> map = new HashMap<String,AlgoHelper>();  
    private Map<String,Integer> vmCountMap = new HashMap<String,Integer>();

    public TempAlgo(DatacenterController dcb) {
        confMap = DepConfList.dcConfMap;
        this.dcc = dcb;
        dcc.addCloudSimEventListener(this);
        if(!this.calledOnce) {
            this.calledOnce = true;
            // Make a new map using dcConfMap that lists 'DataCenter' as a 'key' and 'LinkedList<AlgoAttr>' as 'value'.
            Set<String> keyst =DepConfList.dcConfMap.keySet();
            for(String dataCenter : keyst) {
                LinkedList<AlgoAttr> tmpList = new LinkedList<AlgoAttr>();
                LinkedList<DepConfAttr> list = dcConfMap.get(dataCenter);
                int totalVms = 0;
                for(DepConfAttr o : list) {
                    tmpList.add(new AlgoAttr(o.getVmCount(), o.getMemory()/512, 0));
                    totalVms = totalVms + o.getVmCount();
                }
                Temp_Algo_Static_Var.algoMap.put(dataCenter, tmpList);
                Temp_Algo_Static_Var.vmCountMap.put(dataCenter, totalVms);
            }
            this.algoMap = new HashMap<String, LinkedList<AlgoAttr>>(Temp_Algo_Static_Var.algoMap);
            this.vmCountMap = new HashMap<String,Integer>(Temp_Algo_Static_Var.vmCountMap);
            this.map = new HashMap<String,AlgoHelper>(Temp_Algo_Static_Var.map);
        }
    }

    @Override
    public int getNextAvailableVm() {
        synchronized(this) {
            String dataCenter = this.dcc.getDataCenterName();
            int totalVMs = this.vmCountMap.get(dataCenter);
            AlgoHelper ah = (AlgoHelper)this.map.get(dataCenter);
            int lastIndex = ah.getIndex();
            int lastCount = ah.getLastCount();
            LinkedList<AlgoAttr> list = this.algoMap.get(dataCenter);
            AlgoAttr aAtr = (AlgoAttr)list.get(lastIndex);
            indexChanged = false;
            if(lastCount < totalVMs)  {
                if(aAtr.getRequestAllocated() % aAtr.getWeightCount() == 0) {
                    lastCount = lastCount + 1;
                    this.currentVM = lastCount;
                    if(aAtr.getRequestAllocated() == aAtr.getVmCount() * aAtr.getWeightCount()) {
                        lastIndex++;
                        if(lastIndex != list.size()) {
                            AlgoAttr aAtr_N = (AlgoAttr)list.get(lastIndex);
                            aAtr_N.setRequestAllocated(1);
                            this.indexChanged = true;
                        }
                        if(lastIndex == list.size()) {
                            lastIndex = 0;
                            lastCount = 0;
                            this.currentVM = lastCount;
                            AlgoAttr aAtr_N = (AlgoAttr)list.get(lastIndex);
                            aAtr_N.setRequestAllocated(1);
                            this.indexChanged = true;

                        }
                    }
                }
                if(!this.indexChanged) {
                    aAtr.setRequestAllocated(aAtr.getRequestAllocated() + 1);
                }

                this.map.put(dataCenter, new AlgoHelper(lastIndex, lastCount)); 

                //System.out.println("Current VM : " + this.currentVM + " for data center : " + dataCenter);
                return this.currentVM;
            }}

            System.out.println("--------Before final return statement---------");
            return 0;

    }   

    @Override
    public void cloudSimEventFired(CloudSimEvent e) {
        if(e.getId() == CloudSimEvents.EVENT_CLOUDLET_ALLOCATED_TO_VM) {
            int vmId = (Integer) e.getParameter(Constants.PARAM_VM_ID);
                    busyList.add(vmId);

            System.out.println("+++++++++++++++++++Machine with vmID : " + vmId + " attached");
        }else if(e.getId() == CloudSimEvents.EVENT_VM_FINISHED_CLOUDLET) {
            int vmId = (Integer) e.getParameter(Constants.PARAM_VM_ID);
                            busyList.remove(vmId);
            //System.out.println("+++++++++++++++++++Machine with vmID : " + vmId + " freed");
        }
    }
}

以上代码中,所有的列表都已经按照最高内存排序。整个思路是通过将更多的任务分配给内存更高的机器来平衡内存。每次分配机器后,请求已分配计数器就会增加一次。每组机器都有一个重量计数,该计数是通过将memory_allotted除以512来计算的。方法getNextAvailableVm()同时被多个线程调用。对于3个数据中心,3个线程将同时调用getNextAva...(),但是在不同的类对象上进行。在同一方法中返回的数据中心由先前选择的数据中心代理策略确定。

如何确保我当前返回的机器是空闲的,如果机器不空闲,则分配下一个可用内存最高的机器。我还必须确保处理X个任务的机器即使忙碌也会处理X个任务。

这是这里使用的数据结构的一般描述:

enter image description here

此类的代码托管在这里的Github上

这是Github上完整项目的链接

这里使用的大多数数据结构/类都在该包中。


有趣的项目!我知道大多数人不喜欢这种评论,但你是否看过像Platform Computing这样的专业解决方案? - jboi
@jboi 我想要自己的算法版本。 - saplingPro
2
看那里意味着从他们学习。他们遇到了相同的问题,并用两种方式解决了它。一种方法是,当JVM空闲时,它会拉取工作。第二个是一个延迟参数,他们不运行在共振灾难中,当任务的运行时间和检查周期相等时。这真的值得一看;-) - jboi
JVM需要在它们不再忙碌时报告回来。这本质上是一个池。 - Thorbjørn Ravn Andersen
1个回答

1
也许您正在过度思考问题。一个简单的策略是拥有一个经纪人,该经纪人知道所有待处理的任务。每个任务工作器或线程都会向经纪人请求新的消息/任务以进行处理。经纪人按照被请求的顺序分配工作。这就是 JMS 队列的工作方式。对于可以处理两个任务的 JVM,您可以启动两个线程。
有许多标准的 JMS 可以做到这一点,但我建议看看 ActiveMQ,因为它很容易上手。
请注意,在您的情况下,更简单的解决方案是拥有一台具有 8GB 内存的机器。您可以为服务器购买 8GB 的内存,成本非常低(取决于供应商而定,大约在 $40 至 $150 之间),通过共享资源在一个实例中使用效率更高。我假设您正在考虑比这更大的实例。小于 8GB 的实例最好只需升级即可。
“如何确保我当前返回的机器是空闲的?”这是您的情况,如果您不知道如何判断一台机器是否空闲,我不认为任何人会比您的应用程序更了解。
“如果机器不空闲,我将分配下一个内存最大的机器。”
你需要查看可用内存最多的免费机器,选择其中之一。我不明白除了执行你所说的操作外还有什么限制。
我还必须确保被授权处理X个任务的机器即使当前忙碌也要处理X个任务。
你需要一个数据源或存储来保存此信息。哪里可以运行什么是允许的。在JMS中,您将拥有多个队列,并且仅将某些队列传递给可以处理这些队列的机器。

可能有更好的解决方案。但是我想要做出的改变是在这个类本身。 - saplingPro
因此,当您尝试分配虚拟机时,您会将其保留,而当它被释放时,您会取消保留。 - Peter Lawrey
1
当我尝试分配一个虚拟机时,我只需像getNextAvailableVM()方法中所示一样进行return。任务完成后,机器会自动释放,并通知事件处理程序,即cloudSimEventFired方法。 - saplingPro
好的,你遇到了什么问题? - Peter Lawrey
分配仍将以轮询方式进行,但添加了“忙时转下一台”条款。此外,只能处理4个任务的机器将只获得4个任务。之后,按顺序的下一台机器将获得该任务。 - saplingPro
显示剩余15条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接