2. 中国科学院大学, 北京 100149
2. University of Chinese Academy of Sciences, Beijing 100149, China
云计算经过十几年的发展, 其底层的虚拟化技术已逐渐成熟, 而Docker虚拟化技术由于启动速度快、灵活、轻便等诸多优点逐渐成为云计算领域的热点[1]. 各大云计算厂商也纷纷建立了自己的Docker技术平台[2], 与此同时以Kubernetes[3]为代表的容器编排工具逐渐成为云原生的事实标准, 越来越多的微服务使用Kubernetes进行部署和管理.
Kubernetes最早来源于Google的Borg论文, 理论基础较为完善丰富, 同时扩展性强、自动化程度高, 其主要设计目标是使部署和管理复杂的分布式系统变得容易[3], 它为每个容器分配IP, 并且可以在集群中的任意位置进行访问, 从而提供了一种分布式的环境[4].
Kubernetes由一个master节点和若干worker节点组成, master是整个Kubernetes集群中的控制节点, 包括api server、kube-scheduler、controller-manager三个组件, 其中api server负责接收客户端请求, kube-scheduler负责对Kubernetes中的原子调度单元pod进行调度, controller-manager对Kubernetes中的控制器进行管理, worker节点是工作节点, 用来运行具体的pod. Kubernetes负责将用户的应用打包为的异构的分布式应用程序, 从而使其在一组虚拟机上可用, 因此, 在这种情况下要解决的一个重要的问题就是调度或放置这些容器化应用程序到一组主机上. 在提交部署应用程序时, 编排系统需要考虑应用程序的特定约束, 尽可能充分的利用各种计算资源, 提高集群的负载均衡, 从而降低企业的成本[5].
Kubernetes的资源调度算法由于扩展性较好, 逐渐成为国内外学者研究的热点. 以往的资源调度算法仅仅关注优选过程, 对预选过程关注较少, 且优选过程未考虑网络利用率资源指标, 不能很好的提高集群的负载均衡效率, 且资源利用率的计算方法也较为复杂. 本文对Kubernetes资源调度算法中的预选和优选过程都进行了改进, 且在优选过程中使用了新的资源利用率计算方式, 并且加入了网络利用率这一新的指标, 以最大程度的提高整个集群的负载均衡效率.
2 Kubernetes默认的资源调度算法[6]Kube-scheduler是Kubernetes的集群调度器, 它根据用户创建的pod请求为pod找到一个合适的节点运行在其上面[7], 这就是调度pod的过程. Kubernetes的调度过程分为两部分, 分别是预选和优选过程.
预选过程是根据用户提交的yaml文件, 遍历所有node, 过滤掉不符合用户定义要求的节点, 例如用户定义的pod标签要求使用带有SSD硬盘的节点, 那么显然kube-scheduler就不会把该pod调度到非SSD节点上. 通过分析Kubernetes源码可知, 其内置的部分预选函数有: CheckNodeCondition, 即检查节点是否正常, NoDiskConflict, 即检测磁盘不能冲突, PodToleratesNodeTaints, 即检查pod是否可以容忍节点上的污点等等.
优选过程则是为预选过程选择出的每个节点打分, 本文基于Least Requested Priority和Balanced Resource Allocation两种原始的算法进行, 这两种算法得分为[0, 10]中的整数, 并且每种算法都有一个权重, 默认为1[8]. 其中Least Requested Priority的设计思想为: node上的CPU和memory空闲比例的和越大, 则当前节点得分越高, 这不难理解, 因为CPU和内存空闲比例越大代表当前节点可以容纳更多pod, 不会挤占资源占用率高的节点, 有利于提高整个集群的资源利用率和负载均衡, 其计算公式为:
$ score=\left[ {\frac{{\left( {{{Ccpu}} - {{Rcpu}}} \right)}}{{{{Ccpu}}}}*10 + \frac{{\left( {{{Cmem}} - {{Rmem}}} \right)}}{{{{Cmem}}}}*10} \right]/2{{ }} $ | (1) |
而Balanced Resource Allocation设计思想为计算CPU和内存利用率之间的差值, 差值越小, 说明CPU和内存使用越均衡, 从而得分越高, 其计算公式为:
$ score=\left[ {1 - {{abs}}\left( {\frac{{{{Rcpu}}}}{{{{Ccpu}}}} - \frac{{{{Rmem}}}}{{{{Cmem}}}}} \right)} \right]*10{{ }} $ | (2) |
其中, Rcpu代表节点上已申请的CPU使用量与当前pod申请的CPU容量之和, Rmem代表节点上已申请的内存使用量与当前pod申请的内存容量之和, Ccpu和Cmem分别代表节点总的CPU容量和内存容量.
3 改进的资源调度算法从以上分析可以看出, Kubernetes默认的算法的预选过程要遍历所有节点, 当节点过多会导致预选耗时严重, 因此可以在预选过程中只选出满足条件的节点个数即可, 而无需轮询所有节点, 因为节点的资源利用率是随时变化的, 我们关注的是集群的最终均衡效率, 而不是中间的某一个状态, 轮询所有节点后再打分并不代表最终结果最优. 同时优选过程只考虑了CPU个和内存利用率, 而未关注节点本身的网络利用率, 磁盘利用率等指标, 而当今的互联网应用纷繁复杂, 仅靠CPU和内存指标显然无法反应出集群的整体情况. 下文将对优选过程进行改进, 对节点的CPU、内存、网络、磁盘等指标综合考量, 以改进现有的优选过程算法模型.
3.1 算法设计针对优选过程, 改进的资源调度算法整体思想是合理调度pod以提高整个集群的负载均衡效率, 而对于负载均衡效率的计算, 张玉芳等学者[9]在考虑节点本身性能的前提下, 提出了基于负载权值的计算方法, 使用该文献的方法进行负载的计算. 同时谭莉等[8]提出的考虑节点的性能的算法虽然加上了节点性能的考虑, 但对于互联网应用来说, 网络利用率也是不可忽略的因素, 因此本文在原有的负载均衡计算上加入网络利用率指标, 把CPU、内存、网络、磁盘IO四个维度数据综合考量计算最终得分. 计算公式为:
$ score=\left( {1 - \frac{{{{L}}\left( i \right)}}{{S\left( i \right)}}} \right)*10 $ | (3) |
其中, L(i)表示节点负载, S(i)表示节点性能.
L(i)的计算公式为:
$ {{L}}\left( i \right)={{L}}\left( {{c}} \right) + {{L}}\left( {{m}} \right) + {{L}}\left( {{n}} \right) + {{L(d)}} $ | (4) |
其中, L(c)表示CPU利用率, L(m)表示内存利用率, L(n)表示网络利用率, L(d)表示磁盘利用率.
S(i)的计算公式为:
$ S(i){{= n*}}S\left( {{c}} \right) + S\left( {{m}} \right) + S\left( {{n}} \right) + S{{(d)}} $ | (5) |
其中, n为CPU核数, S(c)表示CPU频率,S(m)表示内存容量, S(n)表示网络速率, S(d)表示磁盘IO速率.
3.2 算法流程 3.2.1 获取节点资源指标在本实验中, 使用两个脚本computeL.sh和computeS.sh分别统计worker节点的CPU、内存、网络、磁盘利用率和CPU核数、内存容量、网络速率、磁盘读写速率, 分别表示资源利用率和节点性能.
3.2.2 实现Kubernetes自定义调度器在Kubernetes官方文档中, 给出了3种实现自定义调度器的方法[10]: (1)修改原有的scheduler模块并重新编译; (2)重新实现自己的调度器模块; (3)实现一个称为“scheduler extender”的调度接口, 供调度器调用决策. 本文使用第2种方式并根据官方例子实现一个简易的调度器, 这里假设只有两个节点, 多个节点同理, 其流程如图1所示.
自定义调度器的运行逻辑为一个轮询过程: 首先获取所有标签为my-scheduler并且尚未绑定节点的pod, 其次在所有worker节点上分别运行computeL.sh和computeS.sh两个脚本获取资源利用率和节点性能, 然后计算得到每个worker节点得分, 最后将当前调度的pod与得分最高的worker节点进行绑定, 这个绑定过程通过向api server发送post请求完成, 从而完成最终的调度. 其伪代码如下:
Input: 各个节点的CPU、内存、IO、网络利用率及CPU核数和频率、内存容量、网络带宽和磁盘容量.
Output: 节点与pod的绑定信息.
CHOSEN<— null
SERVER<—api server
1: while true do
2: for PODNAME in unscheduled where pod.name==my-scheduler do
3: for node in nodes do
4: L<— computeL()
5: S<— computeS()
6: score=(1-L/S)*10
7: CHOSEN<— node[max(score)]
8: end for
9: curl --data {name: $CHOSEN} http://$SERVER/api/v1/namespaces
10: /default/pods/$PODNAME/binding/
11: printf "binding $PODENAME to $CHOSEN "
12: end for
13: sleep 1
14: end while
其中伪代码第4行和第5行的两个函数computeL()和computeS()分别为根据Linux命令获取节点性能指标的两个shell函数.
4 实验对比与分析本实验采用Kubernetes 1.11版本, 通过虚拟机的方式部署在台式机上, 集群中共有1个master和3个worker共4个节点, 配置如表1所示.
4.1 实验过程1)用默认的调度器搭建完集群后, 在集群中起35个pod, 分别执行不同的任务, 然后使用文献[9]中的方法计算集群的均衡负载; 2)删除原来的pod, 使用文献[8]的资源调度算法, 重新起与之前一样的35个pod, 重新计算集群的负载均衡效率; 3)删除原来的pod, 使用自定义调度器, 重新起与之前一样的35个pod, 重新计算集群的负载均衡效率; 4)对比3次的实验结果找出差异. 其中, 集群负载均衡效率计算方法为:
$ H(i)=\frac{{L\left( i \right)/L\left( {avg} \right)}}{{S\left( i \right)/S\left( {avg} \right)}}{\rm{ }}i={\rm{1,2,3}} $ | (6) |
其中, L(avg)代表节点的平均负载, S(avg)代表节点节点平均性能, H(i)越大, 说明集群负载均衡越好, 从而资源调度算法也就越好.
4.2 实验结果
根据式(6)分别计算使用默认调度器、文献[8]的调度器(记为调度器1)和本文实现的自定义调度器(记为调度器2)后集群总体的性能差异, 得到对比结果如表2所示.
图2为使用默认调度器、调度器1和调度器2的情况下集群负载均衡效率柱状图对比, 从实验结果来看, 3个worker节点的集群负载均衡效率对比默认调度器和调度器1均有不同程度的提升, 从而验证了资源调度策略的有效性.
5 结束语
Kubernetes作为微服务架构最核心的编排工具, 其默认资源调度算法的预选过程由于要遍历所有节点, 节点数量较多时比较耗时, 改进的资源调度算法对预选过程做了优化, 提出关注集群最终的资源利用率, 而不关注中间状态, 因此无需遍历所有节点进而提升资源调度效率. 同时针对优选过程仅仅考虑了CPU和内存两个指标, 且只是pod申请的CPU和内存, 并未考虑节点本身的性能指标的问题, 本文在现有的资源调度算法研究基础上, 加入了除CPU、内存和磁盘外的网络利用率和速率, 并实现了自定义调度器来应用改进的资源调度算法, 以期提升集群的整体负载均衡效率. 最后通过实验对比分析验证了算法的有效性.
[1] |
武志学. 云计算虚拟化技术的发展与趋势. 计算机应用, 2017, 37(4): 915-923. DOI:10.11772/j.issn.1001-9081.2017.04.0915 |
[2] |
彭丽苹, 吕晓丹, 蒋朝惠, 等. 基于Docker的云资源弹性调度策略. 计算机应用, 2018, 38(2): 557-562. |
[3] |
Burns B, Grant B, Oppenheimer D, et al. Borg, omega, and kubernetes. Communications of the ACM, 2016, 59(5): 50-57. DOI:10.1145/2890784 |
[4] |
Bernstein D. Containers and cloud: From LXC to docker to kubernetes. IEEE Cloud Computing, 2014, 1(3): 81-84. DOI:10.1109/MCC.2014.51 |
[5] |
Rodriguez M, Buyya R. Container Orchestration With Cost-Efficient Autoscaling in Cloud Computing Environments. Handbook of Research on Multimedia Cyber Security. IGI Global, 2020. 190–213.
|
[6] |
Kubernetes Scheduler. https://kubernetes.io/docs/concepts/scheduling/kube-scheduler/#default-policies. [2019-12-06].
|
[7] |
左灿, 刘晓洁. 一种改进的Kubernetes动态资源调度方法. 数据通信, 2019(2): 50-54. DOI:10.3969/j.issn.1002-5057.2019.02.012 |
[8] |
谭莉, 陶宏才. 一种基于负载均衡的Kubernetes调度改进算法. 成都信息工程大学学报, 2019, 34(3): 228-231. |
[9] |
张玉芳, 魏钦磊, 赵膺. 基于负载权值的负载均衡算法. 计算机应用研究, 2012, 29(12): 4711-4713. DOI:10.3969/j.issn.1001-3695.2012.12.080 |
[10] |
Scheduler extender. https://github.com/kubernetes/commu-nity/blob/master/contributors/design-proposals/scheduling/scheduler_extender.md. [2019-12-06].
|