2021华为软件精英挑战赛(C/C++实现)-苦行僧的实现过程
下面给出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 }
View Code
3.4、后期优化方向
如何初始化购买服务器,如何进行虚拟机的迁移,还有扩容策略是优化的重要方面,可能这是个NP-Hard问题。我在这版代码下,只是实现了虚拟机迁移的一大点,初始化购买服务器和扩容策略是由师兄一起讨论,从最后结果来看,我迁移的算法层面还是欠缺,没有做好程序的高效移植性,c++功底还是偏弱,和师兄的讨论还是少了,对任务的分配还是没有非常明确,个人对工程算法实现层面弱,Debug能力弱,希望后面多多学习。