应用高可用


  • 被抢占的 non-prod 任务放回 pending queue,等待重新调度。

在线业务的命是高可用,一个业务失去了高可用那么就完全没法提供在线服务,这个后果是不可承担的。

在线业务要永远保持在线业务的高可用,比如你要去部署或者扩容在线业务,他就会为你这个在线业务去做调度,当集群里面没有可用资源了怎么办?那么就要去杀掉离线业务,会将离线业务的资源抢过来,将其应用杀掉,将这个资源交给在线业务,这样先让在线业务先跑,但是离线业务不能丢,所以会将离线业务放进pending queue,等什么时候有资源了再重新跑。这样即保证了在线业务的高可用,又保证了离线业务的作业不可丢。

资源利用率

通过在线和离线业务的混合部署,使得资源利用率非常的高,如果我们只跑在线,一定会有些问题,业务波谷的资源是空闲的,为了节省整个资源中心数据成本, 

• 通过将在线任务(prod)和离线任务(non-prod,batch)混合部署,空闲时,离线任务可以充分利用计算资源,繁忙时,在线任务通过抢占的方式保证优先得到执行,合理地利用资源。

-------------------------------------------------------------------------------------------------------------------------------- 

介绍完了基础调度能力之后,下面来了解一下高级调度能力。

 

 

优先级调度


优先级调度和抢占,主要概念有:

  • Priority
  • Preemption

首先来看一下调度过程提到的四个特点,我们如何做到集群的合理利用?

  • 当集群资源足够的话,只需要通过基础调度能力就能组合出合理的使用方式。
  • 但是假如资源不够,我们怎么做到集群的合理利用呢?

通常的策略有两类:

  • 先到先得策略 (FIFO) -简单、相对公平,上手快
  • 优先级策略 (Priority) - 符合日常公司业务特点

在实际生产中,如果使用先到先得策略,是一种不公平的策略因为公司业务里面肯定是有高优先级的业务和低优先级的业务,所以优先级策略会比先到先得策略更能够符合日常公司业务特点。

Kubernetes 高级调度能力 优先级调度/抢占调度_优先级调度

接着介绍一下优先级策略下的优先级调度是什么样的一个概念。比如说有一个 Node 已经被一个 Pod 占用了,这个 Node 只有 2 个 CPU。

另一个高优先级 Pod 来的时候,低优先级的 Pod 应该把这两个 CPU 让给高优先级的 Pod 去使用。低优先级的 Pod 需要回到等待队列,或者是业务重新提交。这样的流程就是优先级抢占调度的一个流程。

在 Kubernetes 里,PodPriority 和 Preemption,就是优先级和抢占的特点,在 v1.14 版本中变成了 stable。并且 PodPriority 和 Preemption 默认都是开启的。

优先级调度配置


怎么使用?

如何使用优先级调度呢?需要创建一个 priorityClass,然后再为每个 Pod 配置上不同的 priorityClassName,这样就完成了优先级以及优先级调度的配置。

Kubernetes 高级调度能力 优先级调度/抢占调度_优先级调度_02

首先来看一下如何创建一个 priorityClass。上图右侧定义了两个 demo:

  • 一个是创建名为 high 的 priorityClass,它是高优先级,得分为 10000;
  • 然后还创建了一个 low 的 priorityClass,它的得分是 100。

并且在第三部分给 Pod 配置上了 high,Pod2 上配置了 low priorityClassName,蓝色部分显示了 pod 的 spec 的配置位置,就是在 spec 里面填写一个 priorityClassName: high。这样 Pod 和 priorityClass 做完配置,就为集群开启了一个 priorityClass 调度。

内置优先级配置

当然 Kubernetes 里面还内置了默认的优先级。如 DefaultpriorityWhenNoDefaultClassExistis,如果集群中没有配置 DefaultpriorityWhenNoDefaultClassExistis,那所有的 Pod 关于此项数值都会被设置成 0。

另一个内置优先级是用户可配置最大优先级限制:HighestUserDefinablePriority = 10000000000(10 亿)

系统级别优先级:SystemCriticalPriority = 20000000000(20 亿)

内置系统级别优先级:

  • system-cluster-critical
  • system-node-critical

这就是优先级调度的基本配置以及内置的优先级配置。

优先级调度过程(资源足够,在调度队列优先出队列,未触发抢占调度)


当做完上面的配置后,整个优先级调度是怎样一个流程呢?下面将会介绍一下简单的过程。

首先介绍一下只触发优先级调度但是没有触发抢占调度的流程。

假如有一个 Pod1 和 Pod2,Pod1 配置了高优先级,Pod2 配置了低优先级。同时提交 Pod1 和 Pod2 到调度队列里。

Kubernetes 高级调度能力 优先级调度/抢占调度_kubernetes_03

调度器处理队列的时候会挑选一个高优先级的 Pod1 进行调度,经过调度过程把 Pod1 绑定到 Node1 上。  

Kubernetes 高级调度能力 优先级调度/抢占调度_离线_04

其次再挑选一个低优先的 Pod2 进行同样的过程,绑定到 Node1 上。

Kubernetes 高级调度能力 优先级调度/抢占调度_优先级_05

这样就完成了一个简单的优先级调度的流程。 

优先级抢占过程(资源不够,触发抢占)


假如高优先级的 Pod 在调度的时候没有资源,那么会是一个怎么样的流程呢?

首先是跟上文同样的场景,但是提前在 Node1 上放置了 Pod0,占去了一部分资源。同样有 Pod1 和 Pod2 待调度,Pod1 的优先级大于 Pod2。

Kubernetes 高级调度能力 优先级调度/抢占调度_离线_06

假如先把 Pod2 调度上去,它经过一系列的调度过程绑定到了 Node1 上。

Kubernetes 高级调度能力 优先级调度/抢占调度_优先级_07

紧接着再调度 Pod1,因为 Node1 上已经存在了两个 Pod,资源不足,所以会遇到调度失败。

Kubernetes 高级调度能力 优先级调度/抢占调度_kubernetes_08

在调度失败时 Pod1 会进入抢占流程,这时会进行整个集群的节点筛选,最后挑出要抢占的 Pod 是 Pod2,此时调度器会把 Pod2 从 Node1 上移除数据。

Kubernetes 高级调度能力 优先级调度/抢占调度_优先级调度_09

再把 Pod1 调度到 Node1 上。这样就完成了一次抢占调度的流程。

Kubernetes 高级调度能力 优先级调度/抢占调度_离线_10

优先级抢占策略


接下来介绍一下具体的抢占策略和抢占的流程是什么样的。

Kubernetes 高级调度能力 优先级调度/抢占调度_离线_11

上图右侧是整个优先级抢占的调度流程,也就是 kube-scheduler 的工作流程。首先一个 Pod 进入抢占的时候,会判断 Pod 是否拥有抢占的资格,有可能上次已经抢占过一次。

如果符合抢占资格,它会先对所有的节点进行一次过滤,过滤出符合这次抢占要求的节点,如果不符合就过滤掉这批节点。

接着从过滤剩下的节点中,挑选出合适的节点进行抢占。这次抢占的过程会模拟一次调度,也就是把上面优先级低的 Pod 先移除出去,再把待抢占的 Pod 尝试能否放置到此节点上。然后通过这个过程选出一批节点,进入下一个过程叫 ProcessPreemptionWithExtenders。这是一个扩展的钩子,用户可以在这里加一些自己抢占节点的策略,如果没有扩展的钩子,这里面是不做任何动作的。

接下来的流程叫做 PickOneNodeForPreemption,就是从上面 selectNodeForPreemption list 里面挑选出最合适的一个节点,这是有一定的策略的。上图左侧简单介绍了一下策略:

  • 优先选择打破 PDB 最少的节点(影响这个节点可用的服务可用性最少)
  • 其次选择待抢占 Pods 中最大优先级最小的节点(对待抢占的pod进行排序,最大优先级的pod必须是所有节点中最小的)
  • 再次选择待抢占 Pods 优先级加和最小的节点
  • 接下来选择待抢占 Pods 数目最小的节点
  • 最后选择拥有最晚启动 Pod 的节点

通过这五步串行策略过滤之后,会选出一个最合适的节点。然后对这个节点上待抢占的 Pod 进行 delete,这样就完成了一次待抢占的过程。

小结:如何做到集群资源合理利用?


上面就简单的介绍了调度的高级策略,这样可以在集群资源紧张的条件下也能够合理的利用集群的资源。 


• 创建自定义的一些优先级类别( PriorityClass


• 给不同类型 Pods 配置不同的优先级( PriorityClassName


• 通过组合不同类型 Pods 运行和优先级抢占让集群资源和调度弹性起来