@maorongrong
2017-12-10T08:50:43.000000Z
字数 13398
阅读 1040
毕设
当公有云引入docker技术进入微服务时代,由于VM、Docker两类虚拟化技术的特性不同,差别,那么Docker所提供的服务级别隔离和VM提供的租户间完全隔离,必将使得云中心以docker-vm-hm的架构提供服务;与以往传统的vm-hm架构相比,docker技术的引入意味着云中心部署算法、调度算法的粒度可进一步缩小为容器级别,为解决云中心高能耗、负载不均、调度迁移VM的时间代价长等问题提供了新思路。
当部署架构由2层的v-h转变为3层d-v-h将存在的问题 | 解决思路 | 解决方法 |
---|---|---|
针对容器新增时希望达到降能耗or均衡负载目标的问题,现有研究仅在docker容器层提出简单的binpack、spread、random部署策略;实际上从整个物理集群的角度去衡量,这些策略仅以directly hosted VMs作为衡量标准,而忽视整个集群running HMs/VMs实际资源分布,对能耗及负载的解决能力不会特别好 | 面向降能耗or均衡负载的目标,使容器放置策略对集群中所有running HMs和VMs均进行能耗or负载的打分,打分模块首先选取所有满足资源约束的selected-VMS,再逐个对selected-VM及其hosted HM进行能耗or负载代价计算,打分最终值为,、分别为控制VM、HM打分占比的非零权重值; 2. 考虑到docker微服务orchestrator scheduler 必须具有的容错能力,因此需要增加动态检测模块实时检测所有容器及其replicas在上一步部署策略安排好的place能否满足independence条件,即同一service的多个replicas不可位于同一Node(此处应为VM),该模块采用BFD微调策略在hosted HM多个VMs间进行选择性换出与纳新。 | 考虑到计算出新增容器放置位置的及时性,选用此类装箱问题最简单有效的启发式算法;针对降能耗目标采用FFD-Based Heuristics类型的FFDSum、FFDProd算法, 针对均衡负载采用Dimensions-aware类型的Dot-Product及Norm-based L2算法;除了算法的各个打分策略按照解决思路编写之外,为了均衡效果更优将Dot-Product算法改进为MaxCosine方式去解决。 |
针对在云中心增加聚合阶段进行降能耗or均衡负载的问题,现有研究均集中在仅以VM作为聚合粒度进行聚合算法的研究,实际上在3层架构下充分考虑到容器易部署、迁移代价为零的特性后,同时将docker、VM作为聚合粒度能够大大提升仅以VM作为聚合粒度时的很多无法再进一步聚合的情况,因此总体上提升降能耗的效果 | 提出新的解决思路,即同时以docker、VM作为聚合粒度。1. 考虑到容器无代价迁移的特性,先在整个容器层进行容器粒度的聚合,再对聚合后实际host容器的VM(一般会节省出一部分running VMs)进行聚合,会进一步节省一批running HMs;2. 增加动态检测模块实时检测所有容器及其replicas在上一步部署策略后的place能否满足independence条件,对不符的容器采用BFD微调策略在hosted HM多个VMs间进行选择性换出与纳新。 | 采用学术界针对VM聚合常采用的heuristics、GA以及BBO算法,按照解决思路的方式进行问题映射和算法调整;分别1. 以降能耗为主的单目标聚合问题进行上述3种算法调整 2. 以降能耗、均衡负载、减少迁移时间为主的多目标问题,采用多目标进化算法(MBBO、GA)进行问题映射和算法调整。 |
架构 | 考虑角度 | 采用方法A | 存在问题 |
---|---|---|---|
2层 | 仅将vm作为容器放置影响因素 | binpack/spread/random | 没有发掘出提升优化程度可能性 |
3层 | 以VM、hosted HM作为放置影响因素 | FFDSum、FFDProd、Dot-Product、L2 | 降能耗、均衡负载会提升,但需要考虑docker service independence,引入独立检测模块进行dependence调整 |
2层 | 仅以VM作为聚合粒度 | 多目标、单目标优化算法 | 没有发掘出提升优化程度可能 |
3层 | docker&VM为聚合粒度 | 学术界常用优化算法先进行docker聚合再进行VM聚合 | 优化程度提高很多,需要加入独立性检测模块进行dependence调整 |
注意: 需要完美解释为何在新增阶段考虑新增容器与HM产生的实际之间的关系??
能耗预测模型沿用李睿在论文中提出的服务器能耗与其CPU利用率成正相关的立方多项式预测模型:
那么,HM的cpu利用率应该以所有运行于其上的VMs实际资源量计算(即运行于各个VM内的容器尺寸之和),还是按照VMs配置的资源量计算???
云中心运行维护海量服务器,每台服务器的资源耗费不尽相同,具体的取决于其上部署的VM配置及其数量。而VM在各个时刻对资源的需求变化很难预测,取决于其上运行的容器所承载的具体服务及其特征。数据中心通常按照用户申请并分配给VM的可使用资源计费,而非以VM实际使用中消耗的资源量计费。因此,本文以分配给VM的资源量作为VM资源量,直接用于能耗预测模型。
但是!!!对于新增容器不造成新增加active VM和HM的情况下,容器放于任何一个VM中都不会改变能耗的预测值,那么为什么还要考虑HM层的资源分布?
针对上述问题那么,可以说以集群中所有 active VMs的cpu资源量作为预测能耗的数据时即为当前集群拓扑的能耗最大值,那么以节省能耗为优化目标的容器新增算法,在进行VM选择时,除了提升最大化VM资源利用率外,应同时考虑当前HM实际能耗对预测能耗的占比最大化,即该HM上所有容器对HM cpu的实际使用率上所有容器对HM的实际占比(相同最大预测能耗下,所有容器当其hosted HM资源使用占比越大说明资源利用越充分)。
综上,若集群能耗计算是以VM需求量作为预测数据时,可以间接认为active HM数量越少,实际物理能耗才会越少,部署策略才会越好(2017-12-6更新)。
分别代表VM的下标和HM的下标;
即位于第个HM的第个VM。
那么新增时,每次都以满足资源约束的VM所在的HM,其上实际的cpu使用率作为能耗数据,取集群能耗最小的放置位置。
最后分别对比仅考虑VM资源分布的docker能耗等代价,和考虑HM资源分布的能耗代价。
采用load index square error平方差
分别计算各维资源利用的均衡程度
该指数大小仅能放映该HM再增加新VM的可能性,值越大能够再容纳新VM可能性越小,当用于说明集群中服务器间负载均衡度时,比说指明服务器load index的均值。实际上并不直观。
故下面提出的负载模型pass
$$)
能上图绝不要是文字说明
传统云计算环境以VM作为降能耗、均衡负载的部署、调度单元,VM的‘庞大’还会牵扯到热迁移的代价问题。而如今促进‘微服务’发展的docker技术引入到云中心,其易构建、分发、部署和无代价迁移的特性也为解决云中心能耗问题提供新的思路。
提供容器云服务的公有云环境,几乎都以docker-vm-hm的3层结构提供服务,主要考虑到VM提供的租户间完全隔离和容器间服务隔离。
该架构下的docker集群调度器,基本以主动(docker swarm+machine)或被动(mesos、openstack magnum)方式感知集群VM层资源分布情况及简单的binpack、spread、random调度策略进行容器的调度。这种局部资源感知力和简单调度策略对于整个集群的能耗节省提供的作用甚微;
而以云中心最有效节省能耗的手段著名的VM聚合策略,在微服务时代很多情况下会出现不可聚合情况,若改变思路提供docker、VM俩种聚合粒度,则能显著降低能耗。
综上,提出面向云中心3层部署架构下的,以降低能耗、均衡负载为目标,同时考虑docker-vm与vm-hm 3个层次及满足微服务独立性的容器动态部署策略。
提出面向降能耗or均衡负载场景的动态新增部署策略
降能耗
以优化改善swarm binpack策略为主要手段,提出综合3个层次的动态部署策略及独立性修复策略。
均衡负载
以优化改善swarm spread策略为主要手段,提出综合3个层次的动态部署策略及独立性修复策略。
独立性修复策略
几乎现有的container orchestrator scheduler均能保证服务容错力,即通过将同一service的不同replicas放置于不同node(VM)的方式保证无论哪个node destroy也不会使得该服务停止。然而对于docker-vm-hm的3层环境由于scheduler只能主动或被动感知到VM层面资源,因此其提供的独立性保证是相对的,而本研究是以综合考虑3个层次为前提提出的绝对独立性检测及修复策略,能够保证即使运行service的某HM destroy也不至于引起service的瘫痪。
提出面向降能耗为目标的双粒度聚合部署策略
能耗预测模型
能耗计算采用的cpu数据?
算法策略
选用算法
提出以容器作为集群真正负载的双粒度均衡放置部署策略
负载均衡分为纵向和横向均衡两种。
纵向是指HM or VM内部各个维度资源的均衡使用,避免因为某一维资源过载导致无法再容纳新VM/docker而造成的其他维度资源的浪费,即避免某一维资源成为容纳新服务的瓶颈。
横向是指集群中所有HMs间每一维资源使用率相对均衡,尽量减少空载和过载的极端情况,避免集群负载检测模块在监测到HM使用率超过过载阈值时开启更多HM提供服务,而造成能耗进一步攀升的情况,因此集群资源横向均衡能够间接稳定能耗。
对于d-v-h部署架构,VM作为完全隔离的提供者必不可少,但实际上容器服务才是真正的集群负载,进行集群负载的均衡时,实际应该以容器作为真正负载均衡的考虑对象。保证容器对HM造成的实际横向、纵向负载均衡,以及容器对VM造成的纵向负载均衡。
VM/HM纵向均衡度模型
HMs横向均衡度模型
算法策略(待修改)
选用算法(待修改)
实验设计
在进行实验对比时,说明由于容器是资源的真正使用者,所以对HM造成的负载均衡应考虑以容器作为真正资源负载。
传统方式利用VM均衡负载
d-v-h下,原来方式以所有docker-VM的映射保持不变,仅对所有VM-HM进行均衡部署策略,对于计算出的策略提出2个衡量方式:
本研究以容器均衡负载
在d-v-h下,负载均衡方案应该保证容器对各个VM、HM的纵向资源均衡,以及容器作为真正负载造成的HMs横向负载均衡度;新的策略计算完毕之后应该提出2个衡量方式:
在Markdown中添加MathJax引擎也很简单,
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>
然后,再使用Tex写公式。$$公式$$表示行间公式,本来Tex中使用\ (公式\ ) 表示行内公式,但因为Markdown中\是转义字符,所以在Markdown中输入行内公式使用 \ \(公式\ \ ),如下代码:
$$x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}$$
\\(x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}\\)
可参考文章——【原创】swarm源码分析(4)---Scheduler和Api
Under the spread strategy, Swarm optimizes for the node with the least number of containers. The binpack strategy causes Swarm to optimize for the node which is most packed. Note that a container occupies resource during its life cycle, including exited state. Users should be aware of this condition to schedule containers. For example, spread strategy only checks number of containers disregarding their states. A node with no active containers but high number of stopped containers may not be selected, defeating the purpose of load sharing. User could either remove stopped containers, or start stopped containers to achieve load spreading. The random strategy, like it sounds, chooses nodes at random regardless of their available CPU or RAM.
Using the spread strategy results in containers spread thinly over many machines. The advantage of this strategy is that if a node goes down you only lose a few containers.
The binpack strategy avoids fragmentation because it leaves room for bigger containers on unused machines. The strategic advantage of binpack is that you use fewer machines as Swarm tries to pack as many containers as it can on a node.
strategy插件化支持()
// PlacementStrategy is the interface for a container placement strategy.
type PlacementStrategy interface {
// Name of the strategy
Name() string
// Initialize performs any initial configuration required by the strategy and returns
// an error if one is encountered.
// If no initial configuration is needed, this may be a no-op and return a nil error.
Initialize() error
// RankAndSort applies the strategy to a list of nodes and ranks them based
// on the best fit given the container configuration. It returns a sorted
// list of nodes (based on their ranks) or an error if there is no
// available node on which to schedule the container.
RankAndSort(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error)
}
var (
strategies []PlacementStrategy
// ErrNotSupported is the error returned when a strategy name does not match
// any supported placement strategy.
ErrNotSupported = errors.New("strategy not supported")
// ErrNoResourcesAvailable is the error returned when there are no resources
// available to schedule a container. This can occur if there are no nodes in
// the cluster or if no node contains sufficient resources for the container.
ErrNoResourcesAvailable = errors.New("no resources available to schedule container")
)
func init() {
strategies = []PlacementStrategy{
&SpreadPlacementStrategy{},
&BinpackPlacementStrategy{},
&RandomPlacementStrategy{},
}
}
// RankAndSort sorts nodes based on the binpack strategy applied to the container config.
func (p *BinpackPlacementStrategy) RankAndSort(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
// for binpack, a healthy node should increase its weight to increase its chance of being selected
// set healthFactor to 10 to make health degree [0, 100] overpower cpu + memory (each in range [0, 100])
const healthFactor int64 = 10
weightedNodes, err := weighNodes(config, nodes, healthFactor)
if err != nil {
return nil, err
}
sort.Sort(sort.Reverse(weightedNodes))
output := make([]*node.Node, len(weightedNodes))
for i, n := range weightedNodes {
output[i] = n.Node
}
return output, nil
}
weighted_node.go :
func weighNodes(config *cluster.ContainerConfig, nodes []*node.Node, healthinessFactor int64) (weightedNodeList, error) {
weightedNodes := weightedNodeList{}
for _, node := range nodes {
nodeMemory := node.TotalMemory
nodeCpus := node.TotalCpus
// Skip nodes that are smaller than the requested resources.
if nodeMemory < int64(config.HostConfig.Memory) || nodeCpus < config.HostConfig.CPUShares {
continue
}
var (
cpuScore int64 = 100
memoryScore int64 = 100
)
if config.HostConfig.CPUShares > 0 {
cpuScore = (node.UsedCpus + config.HostConfig.CPUShares) * 100 / nodeCpus
}
if config.HostConfig.Memory > 0 {
memoryScore = (node.UsedMemory + config.HostConfig.Memory) * 100 / nodeMemory
}
if cpuScore <= 100 && memoryScore <= 100 {
weightedNodes = append(weightedNodes, &weightedNode{Node: node, Weight: cpuScore + memoryScore + healthinessFactor*node.HealthIndicator})
}
}
if len(weightedNodes) == 0 {
return nil, ErrNoResourcesAvailable
}
return weightedNodes, nil
}
swarm/scheduler/strategy/spread.go
// RankAndSort sorts nodes based on the spread strategy applied to the container config.
func (p *SpreadPlacementStrategy) RankAndSort(config *cluster.ContainerConfig, nodes []*node.Node) ([]*node.Node, error) {
// for spread, a healthy node should decrease its weight to increase its chance of being selected
// set healthFactor to -10 to make health degree [0, 100] overpower cpu + memory (each in range [0, 100])
const healthFactor int64 = -10
weightedNodes, err := weighNodes(config, nodes, healthFactor)
if err != nil {
return nil, err
}
sort.Sort(weightedNodes)
output := make([]*node.Node, len(weightedNodes))
for i, n := range weightedNodes {
output[i] = n.Node
}
return output, nil
}
swarm/scheduler/strategy/binpack_test.go:
func createNode(ID string, memory int64, cpus int64) *node.Node {
oc := 0.05
memory = int64(float64(memory) + float64(memory)*oc)
return &node.Node{
ID: ID,
IP: ID,
Addr: ID,
TotalMemory: memory * 1024 * 1024 * 1024,
TotalCpus: cpus,
HealthIndicator: 100,
}
}