下面给出2021华为软件精英挑战赛参与的整个过程,虽然成绩不是很好,但是也是花了一些时间的,希望后面多多学习,多多进步。

  代码已经上传到了Github上:https://github.com/myFrank/huawei_test,代码给出了简易的虚拟机迁移思路和服务器初始化购买及服务器的扩容实现。

1、赛题简介

  区域初赛赛题的考核内容,要求选手根据赛题的相关条件,进行云资源的合理规划与调度,在满足用户所有请求的前提下,减少运营、硬件成本开销。

2、题目定义

2.1、服务器

2.1.1、服务器类型

  在公有云的运营场景中,我们的数据中心可以选购的服务器类型有多种,以下是目前公有云常用的一些服务器类型。

2.1.2、NUMA 架构

  目前主流的服务器都采用了非统一内存访问(NUMA)架构,你可以理解为每台服务器内部都存在两个 NUMA 节点:A 和 B(下文中提到的节点均指 NUMA 节点)。服务器拥有的资源(CPU 和内存)均匀分布在这两个节点上。以 NV603 为例,其 A、B 两个节点分别包含 46C 和 162G 的资源。保证服务器的CPU 核数和内存大小均为偶数。

2.1.3、服务器成本

  数据中心使用每台服务器的成本由两部分构成:硬件成本和能耗成本。硬件成本是在采购服务器时的一次性支出,能耗成本是后续服务器使用过程中的持续支出。为了便于计算,我们以天为单位计算每台服务器的能耗成本。若一台服务器在一天内处于关机状态,则其不需要消耗任何能耗成本,否则我们需要支出其对应的能耗成本。

2.1.4、虚拟机类型

  我们面向用户提供了多种类型的虚拟机售卖服务,用户可以根据自己的需求来自由选购,以下是一些常用的虚拟机类型。 

2.1.5、单节点/双节点部署

  由于服务器存在两个节点,对应的虚拟机也存在两种部署方式:单节点部署或双节点部署。单节点部署指的是一台虚拟机所需的资源(CPU和内存)完全由主机上的一个节点提供;双节点部署指的是一台虚拟机所需的资源(CPU 和内存)必须由一台服务器的两个节点同时提供,并且每个节点提供总需求资源的一半。例如:c3.8xlarge.2 类型的虚拟机需要被部署在一台服务器的 A和 B 两个节点上,A、B 节点分别提供 16C,32G 资源。请注意,一种类型的虚拟机是单节点部署还是双节点部署与其规格没有必然联系,但是双节点部署的虚拟机保证其 CPU 和内存需求量都是偶数。 

2.2、 资源规划和调度

2.2.1、容量约束

  服务器可以用来容纳用户的虚拟机,但是服务器上的任意一个节点(A和 B)上的资源负载(CPU 和内存)均不能超过其容量上限。

2.2.2、请求类型

  用户的请求共分为两种类型:创建请求和删除请求。创建请求表示用户向公有云平台提交的一个创建虚拟机的请求;删除请求表示用户提交的删除一台之前创建的虚拟机的请求。

2.2.3、请求序列

  由一系列请求构成的序列。题目会给出接下来若干天中每一天用户的请求序列,根据每天的请求序列,你需要进行相应的资源规划和调度。

2.2.4、数据中心扩容

  在得知了一天的请求序列后,你可以在实际进行调度前进行一次数据中心扩容。即购买一些新的服务器来容纳后续用户请求的虚拟机,同时你需
要付出所购买服务器相应的硬件成本。你需要指定购买哪些类型的服务器以及购买的数量。初始时你没有任何服务器。

2.2.5、虚拟机迁移

  在完成扩容后,在处理每一天的新请求之前,你还可以对当前存量虚拟机进行一次迁移,即把虚拟机从一台服务器迁移至另一台服务器。对于单节
点部署的虚拟机,将其从一台服务器的 A 节点迁移至 B 节点(或反之)也是允许的。迁移的目的服务器和节点必须有足够的资源容纳所迁移的虚拟机。迁移的虚
拟机总量不超过当前存量虚拟机数量的千分之五。即假设当前有 n 台存量虚拟机,每天你可以迁移的虚拟机总量不得超过 5n/1000 向下取整。

2.2.6、部署虚拟机

  在完成扩容和迁移之后,你需要按顺序处理当天所有的新请求。对于每一个创建虚拟机的新请求,你要为虚拟机指定一台服务器进行部署。若虚拟机是单节点部署的,你还需要指明部署在服务器的 A 节点还是 B 节点。处理请求的过程中,任意一台服务器上每个节点容纳的虚拟机资源总和都不能超出节点本身的资源容量(指 CPU 和内存两个维度)。

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能力弱,希望后面多多学习。

2021华为软件精英挑战赛(C/C++实现)-苦行僧的实现过程的更多相关文章

  1. <路径算法>哈密顿路径变种问题(2016华为软件精英挑战赛初赛)

    原创博客,转载请联系博主! 前言:几天前华为的这个软件精英(算法外包)挑战赛初赛刚刚落幕,其实这次是我第二次参加,只不过去年只入围到了64强(32强是复赛线),最后搞到了一个华为的一顶帽子(感谢交大l ...

  2. Digix2019华为算法精英挑战赛代码

    Digix2019华为算法精英挑战赛代码 最终成绩: 决赛第九 问题 根据手机型号,颜色,用户偏好,手机APP等信息预测用户年龄. https://developer.huawei.com/consu ...

  3. 如何使用华为软件开发云快速部署PHP网站

    华为软件开发云这个工具,从去年推出我就一直在关注,毕竟是华为最新的一款软件开发工具,最近我一直在使用华为软件开发云进行开发项目管理,它有在线编译和构建.云端在线代码检查等功能,编译省去了很多物理机器的 ...

  4. Eclipse安装Git插件以及通过Git导入华为软件开发云项目

    --内容提交-- 1.    Eclipse安装Git插件 2.    在Eclipse中导入华为软件开发云项目, 以及常用Git操作 一. Eclipse安装Git插件 现在从eclipse官网下载 ...

  5. GitHub转华为软件开发云详细教程

    一.复制GitHub的代码库地址 首先,打开Github网页,找到要迁移的代码仓库地址,如下: 点击Clone or Download,出现以下界面 点击Copy toclipboard(复制到粘贴板 ...

  6. 如何将Android Studio与华为软件开发云代码仓库无缝对接(二)

    上篇文章:如何将Android Studio与华为软件开发云代码仓库无缝对接(一) 上一章讲了,如何用Android Studio以软件开发云代码仓库为基础,新建一个项目.接下来,这一章继续讲建好项目 ...

  7. 华为软件开发云对比Jenkins-JavaWeb项目持续部署方式

    一.前言:Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成和持续部署变成可能. 本文 ...

  8. 华为软件开发云CloudIDE功能简测

    华为软件开发云CloudIDE是面向软件开发者的云端开发环境,支持在线编写代码,智能提示,代码提交,代码片段智能搜索等功能. CloudIDE实现了大部分IDE的功能,同时克服了全能IDE的缺点. 一 ...

  9. 看完给跪了:技术大牛总结的Github与华为软件开发云完整对比

    华为软件开发云配置管理 服务和Github是国内外比较有代表性的代码托管平台,它们以git作为版本管理工具,使项目中身处各地的人员可以协同工作,主要操作涉及仓库.分支.提交.pull request等 ...

随机推荐

  1. 蓝桥杯——试题 算法训练 Sereja and Squares

    Java 代码 ```` import java.util.Scanner; public class Main { private static long num = 0; private stat ...

  2. vue v-on-clickaway

    vue v-on-clickaway Custom directive 自定义指令 https://stackoverflow.com/questions/36170425/detect-click- ...

  3. how to convert Map to Object in js

    how to convert Map to Object in js Map to Object just using the ES6 ways Object.fromEntries const lo ...

  4. BattleBots

    BattleBots 搏茨大战 https://battlebots.com/ BiteForce https://www.youtube.com/watch?v=06lyUXuQT_Y xgqfrm ...

  5. Open API collection

    Open API collection online API https://developer.github.com/v3/ https://developer.github.com/v4 http ...

  6. IM & RTC

    IM & RTC 即时通信(IM) & 实时通信(RTC) 场景 即时通信(可靠性高,延时高) 场景包括文字聊天.语音消息发送.文件传输.音视频播放等; 发短信 实时通信(可靠性低,延 ...

  7. Fast-RTPS简介

    RTPS即DDS中的主要核心通信部分.它提供实时高效的去中心化publish/subscribe通信机制.是ROS-2的核心底层通信组件,也是未来机器人/无人驾驶领域一个必然的方向. 资料参考: ht ...

  8. [转]hpp.h与.h的区别

    原文网址:https://blog.csdn.net/liuzhanchen1987/article/details/7270005 hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实 ...

  9. JSON的stringify和parse方法

    一.JSON.parse() 方法用于将一个 JSON 字符串转换为对象. 以下代码为将字符串解析为对象,然后再赋值给对象 //页面初始化完成加载,option是传递的参数 onLoad: funct ...

  10. 零信任三大技术之SDP

    SDP概述 SDP Software Defined Perimeter(软件定义边界),2013 年由云安全联盟 CSA提出. SDP 设计基本原则 1.信息隐身:隐藏服务器地址.端口,使之不被扫描 ...