下面給出2021華為軟體精英挑戰賽參與的整個過程,雖然成績不是很好,但是也是花了一些時間的,希望後面多多學習,多多進步。
程式碼已經上傳到了Github上:https://github.com/myFrank/huawei_test,程式碼給出了簡易的虛擬機器遷移思路和伺服器初始化購買及伺服器的擴容實現。
1、賽題簡介
2、題目定義
2.1、伺服器
2.1.1、伺服器型別
2.1.2、NUMA 架構
2.1.3、伺服器成本
2.1.4、虛擬機器型別
2.1.5、單節點/雙節點部署
2.2、 資源規劃和排程
2.2.1、容量約束
2.2.2、請求型別
2.2.3、請求序列
2.2.4、資料中心擴容
2.2.5、虛擬機器遷移
2.2.6、部署虛擬機器
3、賽題實現(C/C++實現)
由於伺服器的資源是NUMA均勻分佈,所以我們每個伺服器CPU核數 service_cpu和記憶體大小 service_mem,則它在A,B兩個節點均分後,各有service_cpu/2 個cpu核數和 service_mem/2 大小的記憶體。
3.1、下面給出賽題定義的結構體資料型別:
1 /* 2 記錄每天新增/刪減的虛擬機器CPU及記憶體數量及單雙核數量-分單雙節點部署(用結構體) 3 */ 4 struct _per_day_VmTotal_info { 5 6 int deployed_Vm_number = 0; 7 8 int Per_Day_VmTotal_CPU = 0; 9 int Per_Day_VmTotal_MEM = 0; 10 11 int Per_Day_VmTotal_DoubleNodeCPU = 0; 12 int Per_Day_VmTotal_DoubleNodeMEM = 0; 13 14 15 int Per_Day_VmTotal_SingeNode = 0; 16 int Per_Day_VmTotal_DoubleNode = 0; 17 18 }per_day_VmTotal_info; 19 20 21 /* 22 記錄每天購買的伺服器型別,包括 23 購買伺服器的型別 24 伺服器ID(編號從0開始,每增加一臺編號增加1 25 伺服器用途(目前用於為虛擬機器單雙節點部署flag,0表示此編號伺服器用於單節點部署 26 1表示此編號伺服器用於雙節點部署 27 伺服器A節點的剩餘CPU核數(初始為total cpu/2) 28 伺服器B節點的剩餘CPU核數 29 伺服器A節點的剩餘MEM(初始為total mem/2) 30 伺服器B節點的剩餘MEM 31 32 還需要記錄每個伺服器上所負載的虛擬機器的ID,為了migration 33 */ 34 struct _purchase_service_info { 35 string purchase_service_type; 36 37 int purchased_Service_number; 38 39 /*除了記錄伺服器ID(注意伺服器ID對應的資訊可以從其他引數匯出) 40 還需要記錄每個伺服器上所負載的虛擬機器的ID,為了migration*/ 41 unordered_map<int, vector<int>> purchase_service_ID_Info; 42 /* 43 purchase_service_ID_Info[i][j] :s 44 其中i表示 購買的伺服器序號,目前是和伺服器ID一致 45 其中j = 0時,儲存伺服器ID ; j = 1 2 3 時,表示搭建的虛擬機器編號 46 */ 47 48 //vector<int> purchase_service_ID; 49 vector<int> purchase_service_useflag; 50 vector<int> purchase_service_nodeA_remainCPU; 51 vector<int> purchase_service_nodeB_remainCPU; 52 vector<int> purchase_service_nodeA_remainMEM; 53 vector<int> purchase_service_nodeB_remainMEM; 54 55 }purchase_service_info; 56 57 58 /* 59 解析txt檔案時,將可供購買的伺服器型別資訊解析儲存 60 (型號,cpu,記憶體大小,硬體成本,每日能耗成本) 61 */ 62 struct _server_info_stu { 63 string serverType; 64 string cpuCores; 65 string memorySize; 66 string serverCost; 67 string powerCost; 68 }; 69 70 /* 71 解析txt檔案時,將可售賣虛擬機器型別資訊解析儲存 72 (型號,cpu核數,記憶體大小,是否雙節點部署) 73 */ 74 struct _vm_info_stu { 75 string vmType; 76 string vmCpuCores; 77 string vmMemory; 78 string vmTwoNodes; 79 }; 80 81 struct _userVm_requestAdd_info { 82 string op; 83 string reqVmType; 84 string reqId; 85 }; 86 87 struct _userVm_requestDel_info { 88 string op; 89 string reqId; 90 };
3.2、伺服器虛擬機器資料處理
我採用的是unordered_map來儲存每種NUMA伺服器的資訊,虛擬機器為了方便匹配伺服器,設計的資料結構如下:
1 // 伺服器資訊 2 unordered_map<string,vector<int>> serverInfos; 3 // 虛擬機器資訊 4 unordered_map<string,vector<int>> vmInfos;
在解析training-1/2.txt檔案時,將可供購買的伺服器型別和使用者可以建立的虛擬機器型別資訊解析儲存。
1 void generateServer(_server_info_stu *server_info_stu) 2 { 3 string _serverType = ""; 4 for (int i = 1; i < server_info_stu->serverType.size() - 1; i++) { 5 _serverType += server_info_stu->serverType[i]; 6 } 7 8 int _cpuCores = 0, 9 _memorySize = 0, 10 _serverCost = 0, 11 _powerCost = 0; 12 13 for (int i = 0; i < server_info_stu->cpuCores.size() - 1; i++) 14 { 15 _cpuCores = 10 * _cpuCores + server_info_stu->cpuCores[i] - '0'; 16 } 17 18 for (int i = 0; i < server_info_stu->memorySize.size() - 1; i++) 19 { 20 _memorySize = 10 * _memorySize + server_info_stu->memorySize[i] - '0'; 21 } 22 23 for (int i = 0; i < server_info_stu->serverCost.size() - 1; i++) 24 { 25 _serverCost = 10 * _serverCost + server_info_stu->serverCost[i] - '0'; 26 } 27 28 for (int i = 0; i < server_info_stu->powerCost.size() - 1; i++) 29 { 30 _powerCost = 10 * _powerCost + server_info_stu->powerCost[i] - '0'; 31 } 32 33 serverInfos[_serverType] = vector<int>{ _cpuCores / 2 , 34 _cpuCores / 2, 35 _memorySize / 2, 36 _memorySize / 2, 37 _serverCost, 38 _powerCost }; 39 }
1 /* 解析txt檔案時,將可售賣虛擬機器型別資訊解析儲存 2 (型號,cpu核數,記憶體大小,是否雙節點部署) 3 */ 4 void generateVm(_vm_info_stu *vm_info_stu) 5 { 6 string _vmType; 7 8 for (int i = 1; i < vm_info_stu->vmType.size() - 1; i++) { 9 _vmType += vm_info_stu->vmType[i]; 10 } 11 12 int _vmCpuCores = 0, _vmMemory = 0, _vmTwoNodes = 0; 13 for (int i = 0; i < vm_info_stu->vmCpuCores.size() - 1; i++) { 14 _vmCpuCores = _vmCpuCores * 10 + vm_info_stu->vmCpuCores[i] - '0'; 15 } 16 for (int i = 0; i < vm_info_stu->vmMemory.size() - 1; i++) { 17 _vmMemory = _vmMemory * 10 + vm_info_stu->vmMemory[i] - '0'; 18 } 19 if (vm_info_stu->vmTwoNodes[0] == '1') { 20 _vmTwoNodes = 1; 21 } 22 else { 23 _vmTwoNodes = 0; 24 } 25 vmInfos[_vmType] = vector<int>{ _vmCpuCores, 26 _vmMemory, 27 _vmTwoNodes }; 28 }
在讀取檔案時,採用freopen進行重定向到txt檔案,採用cin標準輸入讀入伺服器、虛擬機器資料,並讀人每天虛擬機器請求。具體程式碼如下:
1 //在讀取檔案時,採用freopen進行重定向到txt檔案,採用cin標準輸入讀取資料 2 #ifdef TEST 3 std::freopen(filePath.c_str(), "rb", stdin); 4 #endif 5 int serverNum; 6 7 scanf("%d", &serverNum); 8 9 for (int i = 0; i < serverNum; i++) 10 { 11 cin >> server_info_stu.serverType >> server_info_stu.cpuCores >> server_info_stu.memorySize >> server_info_stu.serverCost >> server_info_stu.powerCost; 12 13 generateServer(&server_info_stu); 14 } 15 16 int vmNumber = 0; 17 scanf("%d", &vmNumber); 18 19 20 21 for (int i = 0; i < vmNumber; i++) { 22 cin >> vm_info_stu.vmType >> vm_info_stu.vmCpuCores >> vm_info_stu.vmMemory >> vm_info_stu.vmTwoNodes; 23 24 generateVm(&vm_info_stu); 25 26 } 27 28 int requestdays = 0, 29 dayRequestNumber = 0; 30 31 scanf("%d", &requestdays);
3.3、伺服器購買初始化
伺服器購買初始化非常重要,需要依據服務的價效比及分析前面天數的虛擬機器CPU、MEM需求,來選擇伺服器,之後分單雙節點分別實現,程式碼如下:
1 // 初始化server,如何初始化購買的伺服器是一個大的優化 2 void Init_BuyServer() 3 { 4 5 string serverType; 6 bool flag = 0; 7 8 findVm_CM_max(); 9 analyzeServerInfo(); 10 11 for (int i = 0; i < 4000; i++) 12 { 13 NodeOnServerInfo[i] = vector<int>{ 0, 0 }; 14 PreNodeOnServerInfo[i] = vector<int>{ 0, 0 }; 15 } 16 17 for (auto it = vec.begin(); it != vec.end(); ++it) 18 { 19 if (flag == 0) 20 { 21 if (serverInfos[it->second][0] >= VM_max_Core && serverInfos[it->second][2] >= VM_max_Mem) //伺服器核心和記憶體是最大虛擬需求的2倍,且價效比高 22 { 23 serverType = it->second; 24 flag = 1; 25 } 26 } 27 } 28 29 flag = 0; 30 31 //serverType = "hostUY41I"; hostTUL1P 32 //(hostTUL1P, 286, 858, 142387, 176) 33 serverType = "hostQ0Y9D"; 34 int n = 700; //目前700最佳 35 36 int server_numberID = 0; 37 38 serverRunVms.resize(4000, 0); 39 string initBuy = "(purchase, "; 40 initBuy += to_string(2) + ")\n"; 41 42 //vector<string> res; 43 res.push_back(initBuy); //(purchase, 2) 44 45 string pauseInfo = "(" + serverType + ", "; 46 pauseInfo += std::to_string(n / 2) + ")\n"; 47 48 res.push_back(pauseInfo); //(hostUY41I, 1250) 49 day_BuyServers_res.push_back((serverType + std::to_string(0) + "," + std::to_string(n / 2))); 50 for (int i = 0; i < n / 2; i++) 51 { 52 //unordered_map<int,vector<int>> sysServerResource; 53 sysServerResource[serverNumber++] = serverInfos[serverType]; 54 SERVERCOST += serverInfos[serverType][4]; 55 56 //記錄購買的虛擬機器資訊,為後面遷移做準備 57 purchase_service_info.purchase_service_ID_Info[server_numberID][0] = server_numberID; //儲存伺服器節點 58 purchase_service_info.purchase_service_nodeA_remainCPU[server_numberID] = serverInfos[serverType][0]; 59 purchase_service_info.purchase_service_nodeB_remainCPU[server_numberID] = serverInfos[serverType][1]; 60 purchase_service_info.purchase_service_nodeA_remainMEM[server_numberID] = serverInfos[serverType][2]; 61 purchase_service_info.purchase_service_nodeB_remainMEM[server_numberID] = serverInfos[serverType][3]; 62 63 // 1-->記錄總的CPU 2->記錄總的MEM 64 purchase_service_info.purchase_service_ID_Info[server_numberID][1] = serverInfos[serverType][0] + serverInfos[serverType][1]; 65 purchase_service_info.purchase_service_ID_Info[server_numberID][2] = serverInfos[serverType][2] + serverInfos[serverType][3]; 66 67 server_numberID++; 68 69 Total_Server_ID[serverNumber - 1] = string{ serverType + std::to_string(0) + "," + std::to_string(serverNumber - 1) }; 70 } 71 //Total_Server_NameID[serverType] = int{ n / 2 - 1}; 72 //ServerTypeBuyOrder[serverType] = int{ 1 }; 73 //(host78BMY, 996, 332, 246869, 310) 74 //(hostUY41I, 676, 994, 243651, 305) 75 serverType = "hostC039T"; 76 pauseInfo = "(" + serverType + ", "; 77 pauseInfo += std::to_string(serverNumber) + ")\n";//(host78BMY, 1250) 78 79 day_BuyServers_res.push_back((serverType + std::to_string(0) + "," + std::to_string(n / 2))); 80 res.push_back(pauseInfo); 81 82 for (int i = 0; i < n / 2; i++) 83 { 84 sysServerResource[serverNumber++] = serverInfos[serverType]; 85 SERVERCOST += serverInfos[serverType][4]; 86 87 //記錄購買的虛擬機器資訊,為後面遷移做準備 88 purchase_service_info.purchase_service_ID_Info[server_numberID][0] = server_numberID; //儲存伺服器節點 89 purchase_service_info.purchase_service_nodeA_remainCPU[server_numberID] = serverInfos[serverType][0]; 90 purchase_service_info.purchase_service_nodeB_remainCPU[server_numberID] = serverInfos[serverType][1]; 91 purchase_service_info.purchase_service_nodeA_remainMEM[server_numberID] = serverInfos[serverType][2]; 92 purchase_service_info.purchase_service_nodeB_remainMEM[server_numberID] = serverInfos[serverType][3]; 93 94 // 1-->記錄CPU 2->記錄MEM 95 purchase_service_info.purchase_service_ID_Info[server_numberID][1] = serverInfos[serverType][0] + serverInfos[serverType][1]; 96 purchase_service_info.purchase_service_ID_Info[server_numberID][2] = serverInfos[serverType][2] + serverInfos[serverType][3]; 97 98 99 Total_Server_ID[serverNumber - 1] = string{ serverType + std::to_string(0) + "," + std::to_string(serverNumber - 1 - n / 2) }; 100 } 101 //Total_Server_NameID[serverType] = int{ n / 2 - 1 }; 102 //ServerTypeBuyOrder[serverType] = int{ 2 }; 103 }
3.4、虛擬機器遷移
虛擬機器遷移主要是利用了之前的結構體,結合虛擬機器的add及del函式,對結構體引數進行處理,伺服器遷移大策略就是編號末尾的伺服器剩餘CPU/MEM比較多的的遷移到前面伺服器上去,儘量佔滿,為了減少伺服器工作成本:
1 for (int _count = (purchase_service_info.purchased_Service_number - 1); _count >= 0; _count--) 2 { 3 //if (purchase_service_info.purchase_service_nodeA_remainCPU[_count] >= 0) 4 //{ 5 float remain_cpu = (purchase_service_info.purchase_service_nodeA_remainCPU[_count] 6 + purchase_service_info.purchase_service_nodeB_remainCPU[_count])*1.0f 7 / purchase_service_info.purchase_service_ID_Info[_count][1] * 1.0f; 8 9 float remain_mem = (purchase_service_info.purchase_service_nodeA_remainMEM[_count] 10 + purchase_service_info.purchase_service_nodeB_remainMEM[_count])*1.0f 11 / purchase_service_info.purchase_service_ID_Info[_count][2] * 1.0f; 12 13 if ((remain_cpu > 0.8f) && (remain_cpu < 0.99f) && (remain_mem > 0.8f) && (remain_mem < 0.99f)) 14 //if ((remain_cpu > 0.8f) && (remain_mem > 0.8f)) 15 { 16 //for (int vm_tra = 3; purchase_service_info.purchase_service_ID_Info[_count][vm_tra] != 0; vm_tra= vm_tra+4) 17 for (int vm_tra = 3; vm_tra <= 239; vm_tra = vm_tra + 4) //30 -- 119 and 40 --159 18 { 19 if (purchase_service_info.purchase_service_ID_Info[_count][vm_tra] > 100) 20 { 21 for (int service_tra = 0; service_tra < 2600; service_tra++) 22 { 23 if (service_tra != _count) //伺服器不能自己遷移到自己本身 24 { 25 //if (purchase_service_info.purchase_service_ID_Info[service_tra][vm_tra + 1]) //如果是雙節點 26 if (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] == 1) //如果是雙節點 27 { 28 if ((purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] >= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2)) 29 && (purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] >= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2)) 30 && (purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] >= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2)) 31 && (purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] >= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2)) 32 ) 33 { 34 #ifdef My_PRINT 35 cout << "nodeA_remain cpu:" << purchase_service_info.purchase_service_nodeA_remainCPU[_count] << " 1 " << purchase_service_info.purchase_service_ID_Info[_count][1] << endl; 36 cout << "nodeB_remain cpu:" << purchase_service_info.purchase_service_nodeB_remainCPU[_count] << " 1 " << purchase_service_info.purchase_service_ID_Info[_count][1] << endl; 37 cout << "nodeA_remain mem:" << purchase_service_info.purchase_service_nodeA_remainMEM[_count] << " 1 " << purchase_service_info.purchase_service_ID_Info[_count][2] << endl; 38 cout << "nodeB_remain mem:" << purchase_service_info.purchase_service_nodeB_remainMEM[_count] << " 1 " << purchase_service_info.purchase_service_ID_Info[_count][2] << endl; 39 #endif 40 41 purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] -= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2); 42 purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] -= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2); 43 purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] -= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2); 44 purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] -= (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2); 45 46 //需要補充選定伺服器移出去的虛擬機器的CPU和MEM 47 purchase_service_info.purchase_service_nodeA_remainCPU[_count] += (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2); 48 purchase_service_info.purchase_service_nodeB_remainCPU[_count] += (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] / 2); 49 purchase_service_info.purchase_service_nodeA_remainMEM[_count] += (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2); 50 purchase_service_info.purchase_service_nodeB_remainMEM[_count] += (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] / 2); 51 52 #ifdef My_PRINT 53 cout << "nodeA_remain cpu:" << purchase_service_info.purchase_service_nodeA_remainCPU[_count] << " 2 " << purchase_service_info.purchase_service_ID_Info[_count][1] << endl; 54 cout << "nodeB_remain cpu:" << purchase_service_info.purchase_service_nodeB_remainCPU[_count] << " 2 " << purchase_service_info.purchase_service_ID_Info[_count][1] << endl; 55 cout << "nodeA_remain mem:" << purchase_service_info.purchase_service_nodeA_remainMEM[_count] << " 2 " << purchase_service_info.purchase_service_ID_Info[_count][2] << endl; 56 cout << "nodeB_remain mem:" << purchase_service_info.purchase_service_nodeB_remainMEM[_count] << " 2 " << purchase_service_info.purchase_service_ID_Info[_count][2] << endl; 57 #endif 58 59 //vmOnServer[vmId] = vector<int>{ serverId,vmCores,vmMemory,1,2 }; 60 61 vmOnServer[std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra])] = vector<int>{ 62 purchase_service_info.purchase_service_ID_Info[service_tra][0], 63 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2], 64 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3],1,2 }; 65 66 67 68 assert(purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] >= 0 69 && purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] >= 0 70 && purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] >= 0 71 && purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] >= 0); 72 73 74 assert((purchase_service_info.purchase_service_ID_Info[_count][1] / 2) >= purchase_service_info.purchase_service_nodeA_remainCPU[_count] 75 && (purchase_service_info.purchase_service_ID_Info[_count][1] / 2) >= purchase_service_info.purchase_service_nodeB_remainCPU[_count] 76 && (purchase_service_info.purchase_service_ID_Info[_count][2] / 2) >= purchase_service_info.purchase_service_nodeA_remainMEM[_count] 77 && (purchase_service_info.purchase_service_ID_Info[_count][2] / 2) >= purchase_service_info.purchase_service_nodeB_remainMEM[_count]); 78 79 string s; 80 string _migration = "migration"; 81 s = "(" + _migration + ", "; 82 s += std::to_string(1) + ")\n";//(migration, count_migration) 83 res.push_back(s); 84 #ifdef My_PRINT 85 cout << s << endl; 86 #endif 87 88 s = "(" + std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra]) + ", "; 89 s += std::to_string(purchase_service_info.purchase_service_ID_Info[service_tra][0]) + ")\n";//(虛擬機器ID, 目的伺服器ID)*/ 90 91 res.push_back(s); 92 93 //新增移入伺服器上虛擬機器的資訊 94 for (int load_vm = 0; load_vm < 60; load_vm++) //因為del的原因,需要解決刪除資訊的方面 95 { 96 if (purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] == 0) 97 { 98 purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra]; 99 purchase_service_info.purchase_service_ID_Info[service_tra][4 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1]; //Nodes 100 purchase_service_info.purchase_service_ID_Info[service_tra][5 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; //CPU 101 purchase_service_info.purchase_service_ID_Info[service_tra][6 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; //MEM 102 103 break; 104 } 105 106 107 } 108 109 //需要刪除從伺服器移走虛擬機器的資訊 110 purchase_service_info.purchase_service_ID_Info[_count][vm_tra] = 0; 111 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] = 0; //Nodes 112 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] = 0; //CPU 113 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] = 0; //MEM 114 115 #ifdef My_PRINT 116 cout << s << endl; 117 #endif 118 119 //計算功耗需要 扣除伺服器的虛擬機器數量 120 serverRunVms[_count]--; 121 serverRunVms[service_tra]++; 122 123 124 count_migration--; 125 126 //break; //如果判斷是可以移植的話,即進行移植,移植完之後 立馬進行下一個虛擬機器 127 return 0; 128 } 129 else 130 { 131 //否則判斷下一個伺服器 CPU和MEM(從小號往大號) 132 } 133 } 134 else if (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] == 2)//需要對A節點點進行選擇移植 不需要除/2 135 { 136 if ((purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] >= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]) 137 && (purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] >= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3])) 138 { 139 140 purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] -= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; 141 purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] -= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; 142 143 //需要補充選定伺服器移出去的虛擬機器的CPU和MEM 144 purchase_service_info.purchase_service_nodeA_remainCPU[_count] += purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; 145 purchase_service_info.purchase_service_nodeA_remainMEM[_count] += purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; 146 147 148 vmOnServer[std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra])] = vector<int>{ 149 purchase_service_info.purchase_service_ID_Info[service_tra][0], 150 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2], 151 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3],1 }; 152 153 154 assert(purchase_service_info.purchase_service_nodeA_remainCPU[service_tra] >= 0 155 && purchase_service_info.purchase_service_nodeA_remainMEM[service_tra] >= 0); 156 157 158 assert(purchase_service_info.purchase_service_ID_Info[_count][1] / 2 >= purchase_service_info.purchase_service_nodeA_remainCPU[_count] 159 && purchase_service_info.purchase_service_ID_Info[_count][2] / 2 >= purchase_service_info.purchase_service_nodeA_remainMEM[_count]); 160 161 string s; 162 string _migration = "migration"; 163 s = "(" + _migration + ", "; 164 s += std::to_string(1) + ")\n";//(migration, count_migration) 165 res.push_back(s); 166 #ifdef My_PRINT 167 cout << s << endl; 168 #endif 169 170 s = "(" + std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra]) + ", "; 171 string _AA_A = "A"; 172 s += std::to_string(purchase_service_info.purchase_service_ID_Info[service_tra][0]) + ", ";//(虛擬機器ID, 目的伺服器ID, A) 173 s += _AA_A + ")\n"; 174 res.push_back(s); 175 176 //新增移入伺服器上虛擬機器的資訊 177 for (int load_vm = 0; load_vm < 60; load_vm++) //因為del的原因,需要解決刪除資訊的方面 178 { 179 if (purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] == 0) 180 { 181 purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra]; 182 purchase_service_info.purchase_service_ID_Info[service_tra][4 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1]; //Nodes 183 purchase_service_info.purchase_service_ID_Info[service_tra][5 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; //CPU 184 purchase_service_info.purchase_service_ID_Info[service_tra][6 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; //MEM 185 186 break; 187 } 188 189 190 } 191 192 //需要刪除從伺服器移走虛擬機器的資訊 193 purchase_service_info.purchase_service_ID_Info[_count][vm_tra] = 0; 194 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] = 0; //Nodes 195 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] = 0; //CPU 196 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] = 0; //MEM 197 #ifdef My_PRINT 198 cout << s << endl; 199 #endif 200 201 //計算功耗需要 扣除伺服器的虛擬機器數量 202 serverRunVms[_count]--; 203 serverRunVms[service_tra]++; 204 205 206 count_migration--; 207 208 //break; //如果判斷是可以移植的話,即進行移植,移植完之後 立馬進行下一個虛擬機器 209 return 0; 210 } 211 else 212 { 213 ; 214 } 215 } 216 else if (purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] == 3)//需要對B節點點進行選擇移植 不需要除/2 217 { 218 if ((purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] >= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]) 219 && (purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] >= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3])) 220 { 221 222 223 purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] -= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; 224 purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] -= purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; 225 226 #ifdef TEST 227 cout << purchase_service_info.purchase_service_nodeB_remainCPU[_count] << purchase_service_info.purchase_service_ID_Info[_count][1] << endl; 228 #endif 229 //需要補充選定伺服器移出去的虛擬機器的CPU和MEM 230 purchase_service_info.purchase_service_nodeB_remainCPU[_count] += purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; 231 purchase_service_info.purchase_service_nodeB_remainMEM[_count] += purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; 232 233 234 vmOnServer[std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra])] = vector<int>{ 235 purchase_service_info.purchase_service_ID_Info[service_tra][0], 236 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2], 237 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3],2 }; 238 239 240 #ifdef TEST 241 cout << purchase_service_info.purchase_service_nodeB_remainCPU[_count] << endl; 242 #endif 243 244 assert(purchase_service_info.purchase_service_nodeB_remainCPU[service_tra] >= 0 245 && purchase_service_info.purchase_service_nodeB_remainMEM[service_tra] >= 0); 246 247 248 assert(purchase_service_info.purchase_service_ID_Info[_count][1] / 2 >= purchase_service_info.purchase_service_nodeB_remainCPU[_count] 249 && purchase_service_info.purchase_service_ID_Info[_count][2] / 2 >= purchase_service_info.purchase_service_nodeB_remainMEM[_count]); 250 251 string s; 252 string _migration = "migration"; 253 s = "(" + _migration + ", "; 254 s += std::to_string(1) + ")\n";//(migration, count_migration) 255 res.push_back(s); 256 #ifdef My_PRINT 257 cout << s << endl; 258 #endif 259 260 s = "(" + std::to_string(purchase_service_info.purchase_service_ID_Info[_count][vm_tra]) + ", "; 261 string _BB_B = "B"; 262 s += std::to_string(purchase_service_info.purchase_service_ID_Info[service_tra][0]) + ", ";//(虛擬機器ID, 目的伺服器ID, B) 263 s += _BB_B + ")\n"; 264 res.push_back(s); 265 266 //新增移入伺服器上虛擬機器的資訊 267 for (int load_vm = 0; load_vm < 60; load_vm++) //因為del的原因,需要解決刪除資訊的方面 268 { 269 if (purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] == 0) 270 { 271 purchase_service_info.purchase_service_ID_Info[service_tra][3 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra]; 272 purchase_service_info.purchase_service_ID_Info[service_tra][4 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1]; //Nodes 273 purchase_service_info.purchase_service_ID_Info[service_tra][5 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2]; //CPU 274 purchase_service_info.purchase_service_ID_Info[service_tra][6 + 4 * load_vm] = purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3]; //MEM 275 276 break; 277 } 278 279 280 } 281 282 //需要刪除從伺服器移走虛擬機器的資訊 283 purchase_service_info.purchase_service_ID_Info[_count][vm_tra] = 0; 284 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 1] = 0; //Nodes 285 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 2] = 0; //CPU 286 purchase_service_info.purchase_service_ID_Info[_count][vm_tra + 3] = 0; //MEM 287 288 289 #ifdef My_PRINT 290 cout << s << endl; 291 #endif 292 293 //計算功耗需要 扣除伺服器的虛擬機器數量 294 serverRunVms[_count]--; 295 serverRunVms[service_tra]++; 296 297 298 count_migration--; 299 300 //break; //如果判斷是可以移植的話,即進行移植,移植完之後 立馬進行下一個虛擬機器 301 return 0; 302 } 303 else 304 { 305 ; 306 } 307 } 308 309 if (count_migration == 0) 310 { 311 return 0; 312 } 313 } 314 else 315 { 316 ; 317 } 318 } 319 } 320 else 321 { 322 ; 323 } 324 } 325 //不移動 326 /* 327 if (no_shift == 1) 328 { 329 string s = "(migration, 0)\n"; 330 res.push_back(s); 331 332 no_shift = 0; 333 } 334 */ 335 336 } 337 else 338 { 339 //否則判斷上一個伺服器 CPU和MEM(從大號往小號) 340 } 341 342 if (count_migration == 0) 343 { 344 return 0; 345 } 346 //} 347 }
3.4、後期優化方向
如何初始化購買伺服器,如何進行虛擬機器的遷移,還有擴容策略是優化的重要方面,可能這是個NP-Hard問題。我在這版程式碼下,只是實現了虛擬機器遷移的一大點,初始化購買伺服器和擴容策略是由師兄一起討論,從最後結果來看,我遷移的演算法層面還是欠缺,沒有做好程式的高效移植性,c++功底還是偏弱,和師兄的討論還是少了,對任務的分配還是沒有非常明確,個人對工程演算法實現層面弱,Debug能力弱,希望後面多多學習。