前言

  • NUMA就是将cpu资源分开,以node 为单位进行分组,每个node都有着独有的cpu、memory等资源
    • 当一个NUMA节点内的资源相交互时,性能将会有很大的提升
    • 但是,如果是两个NUMA节点之间的资源交互将会变得很慢

kubelet多种资源管理器独立分配资源缺乏统一的视角

  • 多种资源管理器在给pod分配设备时,都是独立工作的,不会有一个全局观念,这可能会造成资源分配不合理的问题
  • Topology Manager就是提供全局的视角,为了尽量将资源分配在同一个numa节点下,提升性能

优先原则

  • 某个TopologyHint对于pod而言是不是“优先考虑的”需要遵循如下的规则
    • 01 在满足申请资源个数的前提下
    • 02 选择的资源所涉及的NUMA节点个数最少,就是“优先考虑的”。

HintProvider实现

  • 当前在kubelet中充当HintProvider的总共有3个组件:
    • 一个是CPU Manager
    • 一个是Device Manager
    • 一个是memoryManager
  • 因为Device Manager需要组合多种资源(比如GPU、NIC),所以GetTopologyHints返回map值是数组

什么是kubelet的 Topology Manager

  • 是对节点上CPU、内存和设备局部性有关的优化协调组件

为什么需要Topology Manager

  • 现代计算机的CPU架构多采用NUMA(Non-Uniform Memory Access,非统一内存)架构
  • NUMA就是将cpu资源分开,以node 为单位进行分组,每个node都有着独有的cpu、memory等资源
  • 当一个NUMA节点内的资源相交互时,性能将会有很大的提升
  • 但是,如果是两个NUMA节点之间的资源交互将会变得很慢

比如下面的图示

numa01.png

  • 上面这幅图中有两个NUMA节点存在:

    • NUMA0:由cpu0、cpu1、cpu2、cpu3以及gpu0、nic0和一块本地内存组成
    • NUMA1:由cpu4、cpu5、cpu6、cpu7以及gpu1、nic1和一块本地内存组成
  • 假设某个pod需要的资源清单如下:

    • 4个CPU
    • 200MB内存
    • 1个GPU
    • 1个NIC

各个manager单独工作不能协调的问题

  • 我们知道,在kubelet中cpu和其他外围设备(比如GPU)的分配由不同的组件完成
    • cpu的分配由CPU Manager完成,外围设备由Device Manager完成
  • 它们在给pod分配设备时,都是独立工作的,不会有一个全局观念,这可能会造成资源分配不合理的问题

最佳资源分配的组合

  • 在这个例子中,对于该pod而言比较好的资源组合有两个:
    • 组合1:cpu0、cpu1、cpu2、cpu3、gpu0、nic0
    • 组合2:cpu4、cpu5、cpu6、cpu7、gpu1、nic1
  • 之所以称为比较好的组合,因为这些资源都在一个NUMA节点内

非最佳分配方案

  • 但是CPU Manager和Device Manager是独立工作的,它们不会感知对方给出的分配方案与自己给出的分配方案是不是最优的组合,于是就有可能出现下面这种组合:
    • 组合3:cpu0、cpu1、cpu2、cpu3、gpu1、nic1

Topology Manager 设计的意义

  • 这个分配方案就不是我们想要的。Topology Manager就是为了解决这个问题而设计的,它的目标就是要找到我们例子中的组合1和组合2。

什么是TopologyHint

  • TopologyHint用中文描述为“拓扑提示”,在Topology Manager中,TopologyHint的定义如下:
  • 位置 D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubelet\cm\topologymanager\topology_manager.go
type TopologyHint struct {
    NUMANodeAffinity bitmask.BitMask
    Preferred bool
}

TopologyHint结构体解析

  • 其中NUMANodeAffinity是用bitmask表示的NUMA节点的组合
    • 举个例子,假设有两个NUMA节点(编号分别为0和1),那么可能出现的组合为:[0]、[1]、[0,1]
    • 用bitmask表示为:01,10,11(从右往左开始,组合中有哪一个NUMA节点,那一位就是1)。
  • Preferred代表这个NUMA节点组合对于某个pod而言是不是“优先考虑的”

优先考虑原则

  • 某个TopologyHint对于pod而言是不是“优先考虑的”需要遵循如下的规则
    • 01 在满足申请资源个数的前提下
    • 02 选择的资源所涉及的NUMA节点个数最少,就是“优先考虑的”。

涉及到的numa节点个数最少举例

  • 怎么理解这句话?我们举个例子——假设现在有两个NUMA节点(编号为0和1),每个NUMA节点上都有两个cpu,如果某个pod需要请求两个cpu,那么TopologyHint有如下几个:
    • {01: True}代表从NUMA0上分配两个cpu给pod,这两个cpu都在一个NUMA节点上,涉及的NUMA节点个数最少(为1),所以是“优先考虑的”。
    • {10: True}代表从NUMA1上分配两个cpu给pod,这两个cpu也在一个NUMA节点上,涉及的NUMA节点个数也最少(为1),所以是“优先考虑的”。
    • {11: False}代表从NUMA0和NUMA1上各取一个cpu,涉及的NUMA节点个数为2,所以不是“优先考虑的”。

首先要满足pod资源申请个数前提

  • 那么,是不是所分配的资源必须在一个NUMA节点内,这个方案对于pod而言才是“优先考虑的”呢?
  • 比如现在有两个NUMA节点,每个NUMA节点都只有1块GPU,而某个pod申请了2个GPU
    • 此时{11: True}这个TopologyHint就是“优先考虑的”
    • 因为在满足申请资源个数的前提下,最少要涉及到2个NUMA节点。

Topology Manager的四种策略

Topology Manager提供了四种策略供用户组合各个资源的TopologyHint。这四种策略是:

  • none:什么也不做,与没有开启Topology Manager的效果一样。
  • best-effort: 允许Topology Manager通过组合各个资源提供的TopologyHint,而找到一个最优的TopologyHint
    • 如果没有找到也没关系,节点也会接纳这个Pod。
  • restricted:允许Topology Manager通过组合各个资源提供的TopologyHint,而找到一个最优的TopologyHint
    • 如果没有找到,那么节点会拒绝接纳这个Pod,如果Pod遭到节点拒绝,其状态将变为Terminated。
  • single-numa-node:允许Topology Manager通过组合各个资源提供的TopologyHint,而找到一个最优的TopologyHint
    • 并且这个最优的TopologyHint所涉及的NUMA节点个数是1
    • 如果没有找到,那么节点会拒绝接纳这个Pod,如果Pod遭到节点拒绝,其状态将变为Terminated。

拓扑管理器作用域

  • 拓扑管理器可以在以下不同的作用域内进行资源对齐:
    • container (默认)
    • pod
  • 在 kubelet 启动时,可以使用 --topology-manager-scope 标志来选择其中任一选项。

container 作用域

  • 默认使用的是 container 作用域。
  • 在该作用域内,拓扑管理器依次进行一系列的资源对齐, 也就是,对每一个容器(包含在一个 Pod 里)计算单独的对齐。 换句话说,在该特定的作用域内,没有根据特定的 NUMA 节点集来把容器分组的概念。 实际上,拓扑管理器会把单个容器任意地对齐到 NUMA 节点上。

pod作用域

  • 该作用域允许把一个 Pod 里的所有容器作为一个分组,分配到一个共同的 NUMA 节点集。 也就是,拓扑管理器会把一个 Pod 当成一个整体, 并且试图把整个 Pod(所有容器)分配到一个单个的 NUMA 节点或者一个共同的 NUMA 节点集
  • 以下的例子说明了拓扑管理器在不同的场景下使用的对齐方式:
    • 所有容器可以被分配到一个单一的 NUMA 节点;
    • 所有容器可以被分配到一个共享的 NUMA 节点集。
  • pod 作用域与 single-numa-node 拓扑管理器策略一起使用, 对于延时敏感的工作负载,或者对于进行 IPC 的高吞吐量应用程序,都是特别有价值的。 把这两个选项组合起来,你可以把一个 Pod 里的所有容器都放到一个单个的 NUMA 节点, 使得该 Pod 消除了 NUMA 之间的通信开销。

怎样开启Topology Manager

  • 如果kubernetes版本为1.18及其以上的版本,直接在kubelet的启动项中添加:
--topology-manager-policy=
    [none | best-effort | restricted | single-numa-node]
  • 如果kubernetes版本为1.16到1.18之间,还需要在kubelet启动项中添加:
--feature-gates="...,TopologyManager=<true|false>"

什么是HintProvider

  • 在kubelet源码中,HintProvider的定义如下:
type HintProvider interface {
    // 根据container请求的资源数产生一组TopologyHint
    GetTopologyHints(*v1.Pod, *v1.Container) map[string][]TopologyHint
    // 根据container请求的资源数为container分配具体的资源
    Allocate(*v1.Pod, *v1.Container) error
}
  • 其中GetTopologyHints这个函数用于为某个container产生某种或多种资源的TopologyHint数组
    • 举个例子,假设有两个NUMA节点(编号为0和1)
    • NUMA0上有cpu1和cpu2,NUMA1上有cpu3和cpu4
    • 某个pod请求两个cpu。那么CPU Manager这个HintProvider会调用GetTopologyHints产生如下的TopologyHint:
      • {01: True}代表从NUMA0取2个cpu,并且是“优先考虑的”。
      • {10: True}代表从NUMA1取2个cpu,并且是“优先考虑的”。
      • {11: False}代表从NUM0和NUMA1各取一个cpu,不是“优先考虑的”。

HintProvider的实现

  • 当前在kubelet中充当HintProvider的总共有3个组件:
    • 一个是CPU Manager
    • 一个是Device Manager
    • 一个是memoryManager
  • 这3个组件都实现了HintProvider这个接口的两个方法。

GetTopologyHints 返回数组为了覆盖组合多个资源

  • 另外需要注意的是:GetTopologyHints(*v1.Pod, *v1.Container) map[string][]TopologyHint函数的返回类型是map[string][]TopologyHint,为什么会是这种类型呢?
  • 这是为Device Manager设计的,因为Device Manager需要组合多种资源(比如GPU、NIC),每种资源都返回一组TopologyHint。

本节重点总结

numa架构的基本含义

  • NUMA就是将cpu资源分开,以node 为单位进行分组,每个node都有着独有的cpu、memory等资源
    • 当一个NUMA节点内的资源相交互时,性能将会有很大的提升
    • 但是,如果是两个NUMA节点之间的资源交互将会变得很慢

kubelet多种资源管理器独立分配资源缺乏统一的视角

  • 多种资源管理器在给pod分配设备时,都是独立工作的,不会有一个全局观念,这可能会造成资源分配不合理的问题
  • Topology Manager就是提供全局的视角,为了尽量将资源分配在同一个numa节点下,提升性能

优先原则

  • 某个TopologyHint对于pod而言是不是“优先考虑的”需要遵循如下的规则
    • 01 在满足申请资源个数的前提下
    • 02 选择的资源所涉及的NUMA节点个数最少,就是“优先考虑的”。

HintProvider实现

  • 当前在kubelet中充当HintProvider的总共有3个组件:
    • 一个是CPU Manager
    • 一个是Device Manager
    • 一个是memoryManager
  • 因为Device Manager需要组合多种资源(比如GPU、NIC),所以GetTopologyHints返回map值是数组