2021华为软件精英挑战赛总结

坐标上合赛区,github地址:https://github.com/c-toast/huawei-codecraft2021
我很早就知道了华为软件精英挑战赛。在前几届比赛中,由于自己当时忙于做其他事情,一直没有机会好好地参与其中。今年总算是稍微闲下来一点,于是就和舍友三人组队,成功进入了复赛,但没能进入决赛。我在这个过程中付出了很多心血和时间,虽然最终没能进入决赛,但我从这段经历中得到非常多的收获和提升,也对这段时间的奋斗和努力感到满意。趁着自己关于比赛的记忆还未模糊之前,写下这篇博客记录自己的经历和思考,帮助自己总结与反思这段时间的收获和自己的不足,也供其他人参考我们队的想法和思路。

参赛经历

初赛

初赛赛题已经公布在网上,我的github上也有完整的赛题,这里就不再详述赛题具体内容了,只是简单提一下其中的主要内容。赛题是一个虚拟机放置问题,赛题提供若干种虚拟机型号和服务器型号,并且提供未来若干天的虚拟机添加和虚拟机删除请求,而我们要给出一个购买,迁移,部署的方案以满足这些请求,并使整个过程的代价最小。其中,虚拟机和服务器的资源是二维的,包括CPU数量和内存大小。而服务器的成本包括它的价格和每天的能耗。虚拟机根据其型号可能部署在服务器的一个节点上,也可能部署在两个节点上。服务器任意节点上部署的虚拟机资源总和不能超过该节点资源容量。

在赛题公布后,我首先为我们的算法写一个架构出来。具体的架构如下:
在这里插入图片描述

架构中包含了三个算法部件(Migrater,Deployer,Buyter)分别用于迁移虚拟机,部署虚拟机,购买新服务器。在处理每一天的请求序列时,首先通过迁移算法决定有哪些虚拟机要被迁移,把这些将被迁移的虚拟机和当天新添加的虚拟机一起放在一个list中,交给部署算法。部署算法尽可能地将虚拟机部署到已买的旧服务器上,最后将部署不下的虚拟机交给服务器选型算法。选型算法选择合适的新服务器,并且部署完所有在list中的虚拟机到新服务器上。三个算法都使用CloudOperator进行操作,CloudOperator会记录所有的操作,并整理成符合要求的格式输出。

在最开始的框架里面,我只对算法做了一些非常朴素的实现:没有实现迁移,部署算法采用强制部署的策略,选型算法首先用k-means对虚拟机和服务器分类,然后通过max-min算法模拟部署,最终选择一个剩余资源比较小的服务器。在实现完框架后,我让我的两个队友负责去改进服务器选型算法,我来负责迁移和部署算法。

在设计迁移和部署算法的时候,我首先是去阅读这一领域的论文。一开始我是去看vector bin相关的论文,因为虚拟机放置问题可以转化成vector bin问题。后来我发现其实已经有很多文章直接研究了虚拟机放置这一具体问题,于是我转而去看这些文章。大概扫了十几篇文章,其中有两篇文章对我的算法设计帮助比较大,一篇是Energy efficient virtual machine placement algorithm with balanced and improved resource utilization in a data center,它提出了在多维资源下衡量服务器的资源使用均衡程度的方法。

另外一篇文章是SLA aware cost efficient virtual machines placement in cloud computing,它通过方差来衡量虚拟机资源和服务器资源匹配度。

我主要参考这两篇文章设计我们的迁移部署策略。我的队友则基于我框架中的选型算法的基础上,根据服务器的资源量,价格和能耗等参数设计了一个公式对服务器进行了排序。具体的算法在文章的后面有叙述。到后期我们甚至面向数据编程,对训练集中的数据进行了回归分析,以此为参考改进了公式,成功降低了不少成本,挺进了复赛。

复赛

复赛赛题在初赛赛题的基础上增加了每天可迁移的虚拟机的数目,并且不再提供所有天的请求,而只提供一个时间窗口内的请求,只有在程序输出了一天的结果后,窗口才会向后移动。我们也对我们的程序做了很多尝试和修改。

首先我对我们的代码进行了修改,使其支持这种窗口式的输入输出流程。我还做了另外两个代码上的比较大的修改,一是在处理请求的时候引入时间的概念。二是引入了迁移依赖图。有了这两个工具后,我们的代码就可以在运行部署算法前从服务器上移除那些将被删除和将被迁移的虚拟机,给部署算法留下更多的选择空间。具体的实现方法我写在后边。

关于迁移部署算法部分,我也做了一些改进,但整体架构和思想和之前没有太大变化。

后来我觉得在迁移部署这一块提升的空间已经不是很大,于是我也开始去改进服务器选型算法。在这个过程中,我灵机一动,结合自己看文章看到的game theory的思想和自己的研究方向,想到了一个基于投票的选型方法。虽然该方法确实带来了不少提升,不过由于之前我们和排名前面的大佬的差距实在太大,终究是没能提升多少名次。

复赛现场,题目增加了一个条件,允许我们在某一天大规模整理虚拟机,即允许某一天的虚拟机迁移数目超过上限。这个需求是出乎我意料的,简单讨论过后我们决定先尝试把这个大规模整理的时机定在中间,即在经过了 (总天数)/2 天后,把所有的虚拟机迁移出来,重新部署。但这样做之后我们发现这给我们的迁移依赖图带来了很大的负担,使得我们的程序超时。我想出了一个解决方案,但由于迁移依赖部分的逻辑有点复杂,终究是没能在复赛现场debug完,我们的比赛之旅也到此结束。

最后不得不说华为的招待还是相当不错的,复赛现场有很多小点心和礼物,午饭和晚饭都非常好吃,虽然比赛失利,但免费吃吃喝喝一天的感觉也相当棒,感谢华为!

算法

这里详细介绍一下我们的算法,具体的代码放在我的github上。由于初赛的很多东西我都忘了,所以这里我就只介绍我们用在复赛上的算法版本。

迁移策略

在我们的代码架构里面,迁移算法负责选出被迁移的虚拟机。在设计迁移策略的时候,我把目标定为让服务器的资源使用情况更为均衡。因此整个建议策略分为两步,第一步找出资源使用不均衡的服务器,第二步迁出那些导致服务器资源比失衡的虚拟机。这里的两个关键点是如何衡量服务器的均衡情况和该迁移服务器上的哪些虚拟机。参考了前面提到的一些论文后,我引入server state和fitness的概念,其中server state用来衡量服务器的均衡状况,fitness衡量虚拟机和服务器的匹配程度。

先看server state。这个概念来自于Energy efficient virtual machine placement algorithm with balanced and improved resource utilization in a data center,前面提到这篇论文提出了在多维资源下衡量服务器的资源使用均衡程度的方法。如下图,首先建立一个多维坐标系,每一维坐标对应一维资源的使用率(已使用资源/拥有资源)。在我们的场景里面,资源是二维的,CPU数量和内存大小。那么在下图中,就可以把x轴看作服务器CPU数量的使用率,把y轴看作内存大小的使用率。使用率最高为1,所以每一维坐标的最大值为1。
在这里插入图片描述
根据服务器的多维资源使用率可以算出一个坐标,当这个座标点落在上图中的粉色区域时,说明这个服务器处于资源比较均衡的状态,当落在白色区域时,说明服务器资源使用不均衡。把粉色区域称为安全域和接受域,把白色区域成为拒绝域。其中安全域的大小可以通过R0的值来进行调节。

我们的迁移策略首先就是去找server state在拒绝域上的服务器,然后再在这些服务器中选出被迁移的虚拟机。在选被迁移的虚拟机的时候,我们的算法主要看虚拟机和服务器的匹配程度,并且将这个匹配程度用fitness来描述。前期关于fitness的计算我主要参考了SLA aware cost efficient virtual machines placement in cloud computing这篇文章,它通过各位资源比的方差来衡量虚拟机资源和服务器资源匹配度,计算公式如下图。
在这里插入图片描述
但是后来我从log中发现这个公式好像并不适合我们的场景,它会导致算法将虚拟机从小服务器迁移到大服务器,而不是迁到资源更匹配的服务器,因为服务器越大(即服务器拥有的资源越多), v i / r i v_i/r_i vi/ri的值越小,方差自然也越小。于是我们后期修改了公式,用图来说明我们的公式会更清晰,如下图。A点代表服务器拥有的资源量,这里假设服务器的CPU数是100,内存大小也是100。B点代表虚拟机的资源量,这里虚拟机需要的CPU数是30,内存大小是10。我们用|OC|/|OB|来计算fitness值。
在这里插入图片描述
从直观上理解,这个公式可以理解成,存储单位虚拟机资源所需要的服务器资源。理想状况下,存储1单位虚拟机资源只需要1单位服务器资源,但这只发生在服务器的资源比(CPU数量/内存大小)和虚拟机的资源比完全相同的时候。当它们不同的时候,存储1单位虚拟机资源就需要更多的服务器资源。

当然由于这个公式是我自己想的,没有论文参考,可能是错的,效果也不一定好。

于是,我们的迁移算法通过这个fitness值来选择服务器上该迁移的虚拟机。其实严格意义上我们不是直接用fitness值,而是通过虚拟机和服务器fitness值的排名。具体来说我们对每个虚拟机计算了它和所有服务器的fitness值,并且根据fitness值对服务器进行排序,每一个虚拟机都有这样一个根据fitness排序的服务器序列。当虚拟机所放置服务器在其根据fitness排序的服务器序列中排在前列时,我们就不迁出该虚拟机,否则则迁出该虚拟机。

迁移算法还有很多其它细节,比方说对服务器按照资源使用程度排序,对虚拟机按照资源大小排序等等。另外,我还使用server state来衡量服务器的节点均衡状况,如果两个服务器的节点出现不均衡的状况,例如一个节点的资源使用率非常高,另一个节点的资源使用率非常低,则会从资源使用率高的节点中迁出一些虚拟机。在后期我还使用了动态选择迁移策略的方法,当未来一定天数的虚拟机请求资源量小于已有服务器的资源量时,则不再使用上述迁移策略,而是转而将部分服务器清空,尽可能地减少能源损耗。

部署策略

部署算法和迁移算法一样,都使用server state和fitness作为参考。值得一提的是,我采用了多轮部署的策略。在第一轮部署中,会尝试将虚拟机部署到fitness排名前10的服务器当中,第二轮则尝试将虚拟机部署到fitness排名10-20的服务器当中,第三轮则是20-30。第四轮则根据server state进行部署,当虚拟机部署到服务器后,服务器的server state处于安全域的时候,则接受该部署,在该轮部署中,安全域会设置得比较小。后面两轮同样是根据server state进行部署,只不过安全域会设置得大一些。最后一轮则是强制部署,只要虚拟机能塞进服务器里面,则接受该部署。在部署之前,会对虚拟机列表和服务器列表进行排序,服务器按照空满程度从满到空进行排序。虚拟机按照资源大小有大到小进行排序。

选型策略

我们一开始的选型策略非常简单,k-means分类+max-min模拟部署。我的队友后来设计了一个公式用来衡量服务器单位资源的cost: P r i c e + E n e r g y C o s t ∗ ( T o t a l D a y − C u r r e n t D a y ) M e m e o r y S i z e + 2 ∗ C P U N u m \frac{Price+EnergyCost*(TotalDay-CurrentDay)}{MemeorySize+2*CPUNum} MemeorySize+2CPUNumPrice+EnergyCost(TotalDayCurrentDay)。我们按照该公式在选型的时候对服务器排序,在初赛的时候带来了很多提升,成功让我们进入复赛。

后来我想到,之前自己一直站在一个上帝视角来为虚拟机购买服务器,能不能反过来,让每个虚拟机自己决定它们应该放在哪。于是我结合自己看文章的时候看到的game theory思想,结合自己的研究方向,想到了一个基于投票的选型方法。

这个方法用一句话来概括就是让每个虚拟机去为它们想待的服务器投票,然后买下收到票数最多的服务器。虚拟机待在某个服务器上的倾向程度则由该服务器的cost以及该服务器和虚拟机的fitness决定。前面我们提到fitness是存储单位虚拟机资源所需要的服务器资源,这个值乘上我们前面的cost公式,就可以理解成单位虚拟机资源存储在该服务器上的代价,这个代价越小,虚拟机则越愿意待在该服务器上。我为每个虚拟机分配了若干不同面额的选票,每个虚拟机将面额最大的选票投给代价最小的服务器,把面额第二大的选票投给代价次小的服务器。这个选票面额还要乘上虚拟机的资源大小,这样越大的虚拟机话语权越重。在一轮投票结束后,买下票数最多的服务器,然后按照fitness由小到大往新买的服务器里面塞虚拟机,直到塞不下为止。这时候剩下的虚拟机开始下一轮投票。

为了能够利用后验信息,我还让未来的虚拟机也参与到当前的投票中,只不过这些未来虚拟机的选票面额会小一些。

目前该算法只是从服务器的cost,服务器和虚拟机的fitness以及虚拟机的大小以及未来虚拟机的需求出发,并没有去考虑服务器的资源使用率,可能这是可以继续改进的一个点。关于cost的式子和fitness的式子以及关于两者相乘的结果也并不十分严谨,都只是我们凭直觉想出来的,可能有更好的计算方法。

其它设计

时刻

在我一开始设计的架构中,是在一天的末尾才处理删除请求。这会导致我们的算法没办法在当天使用由于虚拟机删除而返还的服务器资源。为了解决这个问题,我引入了时刻的概念。
我根据一天中请求的数目将一天划分成若干时刻,每一个时刻处理一个请求,当处理不同时刻的请求时,会返回该时刻下服务器的状态,比方说某个服务器在第2个时刻删除了一个虚拟机,那么当处理第1个时刻的add请求时,则算法看到的是未删除虚拟机的服务器,当处理第3个时刻的add请求时,算法看到的是删除了虚拟机的服务器。

依赖图

在一开始的架构中,迁移算法并不会真正地把虚拟机从源服务器中迁出来,而只是对将被迁移地虚拟机做一个标记。只有部署算法部署被迁移的虚拟机的时候,才会从源服务器中删除迁移虚拟机的资源,将其部署到其它服务器上。我认为更好的做法应该是在迁移算法中就把将被迁移的虚拟机资源从服务器上删掉,这样部署算法会有更多的可选择的服务器。但这样就会引发迁移依赖问题。比方说现在A服务器上有虚拟机a将被迁移,B服务器上有服务器b将被迁移,我们决定将a迁到B服务器上,但是B服务器在其上的b虚拟机被迁走之前,并没有足够的空间来容纳a,我们就说a依赖b,也就是b的迁移必须发生在a之前。

为了解决这个问题,我使用有向无环图来建立虚拟机与虚拟机之间的依赖关系,这里称其为依赖图。在部署之前,会考虑本次部署导致的依赖关系是否会导致依赖图形成环,如果会,则取消这次部署,如果不会,则接受部署并更新依赖图。最后根据依赖图来决定迁移操作在输出结果的顺序。

总结与反思

算法为王。华为软件精英挑战赛是一个考究算法的比赛,但在这次比赛中,我花了很多精力去思考该怎么把代码写好,写漂亮,而导致自己没有更多时间和精力去好好推敲和尝试算法。这可能是我们止步于复赛的原因。未来还有接近两年的研究生生活,我应该将更多的精力投入到算法、数学的学习上。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值