Kubelet從入門到放棄:拓撲管理(下)

<Kubelet從入門到放棄>系列將對Kubelet組件由基礎知識到源碼進行深刻梳理。上一篇zouyee帶各位看了CPU 管理的相關內容,其中說起拓撲管理,本文將對此進行詳細剖析,拓撲管理在Kubernetes 1.18時提高爲Beta。 TopologyManager功能可實現CPU、內存和外圍設備(例如SR-IOV VF和GPU)的NUMA對齊,從而使集羣知足低延遲需求。node

3、源碼分析算法

對於拓撲管理器代碼分析,咱們從兩個方面進行:api

1)Kubelet初始化時,涉及拓撲管理的相關操做markdown

2)Kubelet運行時,涉及拓撲管理的相關操做,深刻分析拓撲管理結構邏輯架構

3.1 Kubelet初始化app

關於Kubelet初始化,咱們在以CPU manager結合拓撲管理器的啓動圖(當前爲CPU manager、memory manager、device manager構成資源分配管理器,其屬於Container Manager模塊的子系統)進行說明。框架

對於上圖的內容,zouyee總結流程以下:less

一、在命令行啓動部分,Kubelet中調用NewContainerManager構建ContainerManager

二、NewContainerManager函數調用topologymanager.NewManager構建拓撲管理器,不然未啓用拓撲管理器,則構建fake

三、NewContainerManager函數分別調用cpu、memory及device提供的NewManager構建相關管理器

四、若拓撲管理特性開啓,則拓撲管理器使用AddHintPriovider方法將CPU、memory及device管理器加入管理,上述三種資源分配器,須要實現HintPriovider接口。

五、回到命令行啓動部分,調用NewMainKubelet(),構建Kubelet結構體

六、構建Kubelet結構體時,將CPU、memory管理器(沒有device)跟拓撲管理器封裝爲InternalContainerLifecycle接口,其實現Pod相關的生命週期資源管理操做,涉及資源分配回收相關的是PreStartContainer、PostStopContainer方法,可參看具體實現。

七、構建Kubelet結構體時,調用AddPodmitHandler將GetAllocateResourcesPodAdmitHandler方法加入到Pod准入插件中,在Pod建立時,資源預分配檢查,其中GetAllocateResourcesPodAdmitHandler根據是否開啓拓撲管理,決定是返回拓撲管理Admit接口,仍是使用cpu、memory及device構成資源分配器,實現Admit接口。

八、構建Kubelet結構體後,調用ContainerManager的Start方法,ContainerManager在Start方法中調用CPU、memeory及device管理器的Start方法,其作一些處理工做並孵化一個goroutine,執行reconcileState()

注:關於上述啓動流程的代碼解釋,能夠返回識透CPU一文。
複製代碼

3.2 Kubelet運行時ide

Kubelet運行時,涉及到拓撲管理、資源分配的就是對於Pod處理流程,zouyee總結以下:函數

一、PodConfig從apiserver、file及http三處接受Pod,調用Updates()返回channel,內容爲Pod列表及類型。

二、Kubelet調用Run方法,處理PodConfig的Updates()返回的channel

三、在Run方法內部,Kubelet調用syncLoop,而在syncLoop內部,調用syncLoopIteration

四、在syncLoopIteration中,當configCh(即PodConfig調用的Updates())返回的pod類型爲ADD時,執行handler.HandlePodAdditions,在HandlePodAdditions中,處理流程以下:當pod狀態爲非Termination時,Kubelet遍歷admitHandlers,調用Admit方法。

注:syncLoopIteration中除了configCh,還有其餘channel(plegCh、syncCh、housekeepingCh及livenessManager)其中plegCh、syncCh及livenessManager三類channel中調用的HandlePodAddtion、HandlePodReconcile、HandlePodSyncs及HandlePodUpdates都涉及dispatch方法調用,還記得Kubelet流程中,將CPU管理器、內存管理器跟拓撲管理器封裝爲InternalContainerLifecycle接口,其實現Pod相關的生命週期資源管理操做,涉及CPU、內存相關的是PreStartContainer方法,其調用AddContainer方法,後續統一介紹。

五、在介紹Kubelet啓動時,調用AddPodmitHandler將GetAllocateResourcesPodAdmitHandler方法加入到admitHandlers中,所以在調用Admit方法的操做,涉及到拓撲管理的也就是GetAllocateResourcesPodAdmitHandler,那麼接下來就接受一下該方法。

六、在Kublet的GetAllocateResourcesPodAdmitHandler方法的處理邏輯爲:當啓用拓撲特性時,資源分配由拓撲管理器統一接管,若是未啓用,則爲cpu管理器、內存管理器及設備管理器分別管理,本文只介紹啓用拓撲管理器的狀況。

七、啓用拓撲管理器後,Kublet的GetAllocateResourcesPodAdmitHandler返回的Admit接口類型,由拓撲管理器實現,後續統一介紹。

上述流程即爲Pod大體的處理流程,下面介紹拓撲結構初始化、AddContainer及Admit方法。

1)拓撲結構初始化

拓撲結構初始化函數爲pkg/kubelet/cm/topologymanager/topology_manager.go:119

// NewManager creates a new TopologyManager based on provided policy and scope
func NewManager(topology []cadvisorapi.Node, topologyPolicyName string, topologyScopeName string) (Manager, error) {
   // a. 根據cadvisor數據初始化numa信息
   var numaNodes []int
   for _, node := range topology {
      numaNodes = append(numaNodes, node.Id)
   }
	 // b. 判斷策略爲非none時,numa節點數量是否超過8,若超過,則返回錯誤
   if topologyPolicyName != PolicyNone && len(numaNodes) > maxAllowableNUMANodes {
      return nil, fmt.Errorf("unsupported on machines with more than %v NUMA Nodes", maxAllowableNUMANodes)
   }
	 // c. 根據傳入policy名稱,進行初始化policy
   var policy Policy
   switch topologyPolicyName {

   case PolicyNone:
      policy = NewNonePolicy()

   case PolicyBestEffort:
      policy = NewBestEffortPolicy(numaNodes)

   case PolicyRestricted:
      policy = NewRestrictedPolicy(numaNodes)

   case PolicySingleNumaNode:
      policy = NewSingleNumaNodePolicy(numaNodes)

   default:
      return nil, fmt.Errorf("unknown policy: \"%s\"", topologyPolicyName)
   }
	 // d. 根據傳入scope名稱,以初始化policy結構體初始化scope
   var scope Scope
   switch topologyScopeName {

   case containerTopologyScope:
      scope = NewContainerScope(policy)

   case podTopologyScope:
      scope = NewPodScope(policy)

   default:
      return nil, fmt.Errorf("unknown scope: \"%s\"", topologyScopeName)
   }
	 // e. 封裝scope,返回manager結構體
   manager := &manager{
      scope: scope,
   }

   

	a. 根據cadvisor數據初始化numa信息

	b. 判斷策略爲非none時,numa節點數量是否超過8,若超過,則返回錯誤

	c. 根據傳入policy名稱,進行初始化policy

	d. 根據傳入scope名稱,以初始化policy結構體初始化scope

	e. 封裝scope,返回manager結構體

2) AddContainer

	AddContainer實際調用scope的方法:pkg/kubelet/cm/topologymanager/scope.go:97

func (s *scope) AddContainer(pod *v1.Pod, containerID string) error {
   s.mutex.Lock()
   defer s.mutex.Unlock()

   s.podMap[containerID] = string(pod.UID)
   return nil
}

	該處只作簡單字典加入操做。

3)Admit

	Admit函數調用:pkg/kubelet/cm/topologymanager/topology_manager.go:186,根據scope類型分別調用不一樣的實現:

	a、container
複製代碼

pkg/kubelet/cm/topologymanager/scope_container.go:45

func (s *containerScope) Admit(pod *v1.Pod) lifecycle.PodAdmitResult {
   // Exception - Policy : none
   // 1. 策略爲none,則跳過
   if s.policy.Name() == PolicyNone {
      return s.admitPolicyNone(pod)
   }
	 // 2. 遍歷init及常規容器
   for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
   		// 2.1 計算親和性,判斷是否准入
      bestHint, admit := s.calculateAffinity(pod, &container)
      

      if !admit {
         return topologyAffinityError()
      }
      // 2.2 記錄分配結果
      s.setTopologyHints(string(pod.UID), container.Name, bestHint)
			// 2.3 調用hint provider分配資源
      err := s.allocateAlignedResources(pod, &container)
      if err != nil {
         return unexpectedAdmissionError(err)
      }
   }
   return admitPod()
}

	b、pod
複製代碼

pkg/kubelet/cm/topologymanager/scope_pod.go:45

func (s *podScope) Admit(pod *v1.Pod) lifecycle.PodAdmitResult {
   // Exception - Policy : none
   // 1. 策略爲none,則跳過
   if s.policy.Name() == PolicyNone {
      return s.admitPolicyNone(pod)
   }
	// 2 計算親和性,判斷是否准入
   bestHint, admit := s.calculateAffinity(pod)
   
   if !admit {
      return topologyAffinityError()
   }
		// 3. 遍歷init及常規容器
   for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
      // 3.1 記錄分配結果
      s.setTopologyHints(string(pod.UID), container.Name, bestHint)
			// 3.2 調用hint provider分配資源
      err := s.allocateAlignedResources(pod, &container)
      if err != nil {
         return unexpectedAdmissionError(err)
      }
   }
   return admitPod()
}

	具體說明見代碼註釋,須要說明的是scope爲container與pod的區別主要在計算親和性,判斷是否准入的階段,一樣也反應了scope與container的粒度,後續重點介紹calculateAffinity方法。

	下面zouyee帶各位總結一下拓撲管理器的Admit邏輯。

	拓撲管理器爲組件定義Hint Providers的接口,以發送和接收拓撲信息,CPU、memory及device都實現該接口,拓撲管理器調用AddHintPriovider加入到管理器,其中拓撲信息表示可用的 NUMA 節點和首選分配指示的位掩碼。 拓撲管理器策略對所提供的hint執行一組操做,並根據策略獲取最優解;若是存儲了與預期不符的hint,則該建議的優選字段設置爲 false。所選建議可用來決定節點接受或拒絕 Pod 。 以後,hint結果存儲在拓撲管理器中,供Hint Providers進行資源分配決策時使用。

對於上述兩種做用域(container及pod)的calculateAffinity通用流程,彙總以下(忽略計算親和性的差別):
複製代碼

對於上圖的內容,zouyee總結流程以下:

  1. 遍歷容器中的全部容器(scope爲pod跟container的差異,上面已經說明)
  2. 對於每一個容器,針對容器請求的每種拓撲感知資源類型(例如gpu-vendor.com/gpu、nic-vendor.com/nic、cpu等),從一組HintProviders中獲取TopologyHints。
  3. 使用選定的策略,合併收集到的TopologyHints以找到最佳hint,該hint能夠在全部資源類型之間對齊資源分配。
  4. 循環返回hintHintProviders集合,指示他們使用合併的hint來分配他們管理的資源。
  5. 若是上述步驟中的任一個失敗或根據所選策略沒法知足對齊要求,Kubelet將不會准入該pod。

下面zouyee根據下圖依次介紹拓撲管理器涉及的結構體。

a. TopologyHints

拓撲hint對一組約束進行編碼,記錄能夠知足給定的資源請求。 目前,咱們惟一考慮的約束是NUMA對齊。 定義以下:

type TopologyHint struct {
    NUMANodeAffinity bitmask.BitMask
    Preferred bool
}
複製代碼

NUMANodeAffinity字段表示能夠知足資源請求的NUMA節點個數的位掩碼,是bitmask類型。 例如,在2個NUMA節點的系統上,可能的掩碼包括:

{00}, {01}, {10}, {11}
複製代碼

Preferred是用來管理NUMANodeAffinity是否生效的布爾類型,若是Preferred爲true那麼當前的親和度有效,若是爲false那麼當前的親和度無效。 使用best-effort策略時,在生成最佳hint時,優先hint將優先於非優先hint。 使用restricted和single-numa-node策略時,將拒絕非優先hint。

HintProvider爲每一個能夠知足該資源請求的NUMA節點的掩碼生成一個TopologyHint。 若是掩碼不能知足要求,則將其省略。 例如,當被要求分配2個資源時,HintProvider可能在具備2個NUMA節點的系統上提供如下hint。 這些hint編碼表明的兩種資源能夠都來自單個NUMA節點(0或1),也能夠各自來自不一樣的NUMA節點。

{01: True}, {10: True}, {11: False}
複製代碼

當且僅當NUMANodeAffinity表明的信息能夠知足資源請求的最小NUMA節點集時,全部HintProvider纔會將Preferred字段設置爲True。

{0011: True}, {0111: False}, {1011: False}, {1111: False}
複製代碼

若是在其餘容器釋放資源以前沒法知足實際的首選分配,則HintProvider返回全部Preferred字段設置爲False的hint列表。考慮如下場景:

  1. 當前,除2個CPU外的全部CPU均已分配給容器
  2. 剩餘的2個CPU在不一樣的NUMA節點上
  3. 一個新的容器請求2個CPU

在上述狀況下,生成的惟一hint是{11:False}而不是{11:True}。由於能夠從該系統上的同一NUMA節點分配2個CPU(雖然當前的分配狀態,還不能當即分配),在能夠知足最小對齊方式時,使pod進入失敗並重試部署總比選擇以次優對齊方式調度pod更好。

b. HintProviders

目前,Kubernetes中僅有的HintProviders是CPUManager、MemoryManager及DeviceManager。 拓撲管理器既從HintProviders收集TopologyHint,又使用合併的最佳hint調用資源分配。 HintProviders實現如下接口:

type HintProvider interface {
    GetTopologyHints(*v1.Pod, *v1.Container) map[string][]TopologyHint
    Allocate(*v1.Pod, *v1.Container) error
}
複製代碼

注意:GetTopologyHints返回一個map [string] [] TopologyHint。 這使單個HintProvider能夠提供多種資源類型的hint。 例如,DeviceManager能夠返回插件註冊的多種資源類型。

當HintProvider生成hint時,僅考慮如何知足系統上當前可用資源的對齊方式。 不考慮已經分配給其餘容器的任何資源。

例如,考慮圖1中的系統,如下兩個容器請求資源:

# Container0
spec:
    containers:
    - name: numa-aligned-container0
      image: alpine
      resources:
          limits:
              cpu: 2
              memory: 200Mi
              gpu-vendor.com/gpu: 1
              nic-vendor.com/nic: 1

# Container1
spec:
    containers:
    - name: numa-aligned-container1
      image: alpine
      resources:
          limits:
              cpu: 2
              memory: 200Mi
              gpu-vendor.com/gpu: 1
              nic-vendor.com/nic: 1
複製代碼

若是Container0是要在系統上分配的第一個容器,則當前三種拓撲感知資源類型生成如下hint集:

cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{01: True}, {10: True}}
nic-vendor.com/nic: {{01: True}, {10: True}}
複製代碼

已經對齊的資源分配:

{cpu: {0, 1}, gpu: 0, nic: 0}
複製代碼

在考慮Container1時,上述資源假定爲不可用,所以將生成如下hint集:

cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{10: True}}
nic-vendor.com/nic: {{10: True}}
複製代碼

分配的對齊資源:

{cpu: {4, 5}, gpu: 1, nic: 1}
複製代碼

注意:HintProviders調用Allocate的時,並未採用合併的最佳hint, 而是經過TopologyManager實現的Store接口,HintProviders經過該接口,獲取生成的hint:

type Store interface {
    GetAffinity(podUID string, containerName string) TopologyHint
}
複製代碼

c. Policy.Merge

每一個策略都實現了合併方法,各自實現如何將全部HintProviders生成的TopologyHint集合合併到單個TopologyHint中,該TopologyHint用於提供已對齊的資源分配信息。

// 1. bestEffort
func (p *bestEffortPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
	filteredProvidersHints := filterProvidersHints(providersHints)
	bestHint := mergeFilteredHints(p.numaNodes, filteredProvidersHints)
	admit := p.canAdmitPodResult(&bestHint)
	return bestHint, admit
}
// 2. restrict
func (p *restrictedPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
	filteredHints := filterProvidersHints(providersHints)
	hint := mergeFilteredHints(p.numaNodes, filteredHints)
	admit := p.canAdmitPodResult(&hint)
	return hint, admit
}
// 3. sigle-numa-node
func (p *singleNumaNodePolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
   filteredHints := filterProvidersHints(providersHints)
   // Filter to only include don't cares and hints with a single NUMA node.
   singleNumaHints := filterSingleNumaHints(filteredHints)
   bestHint := mergeFilteredHints(p.numaNodes, singleNumaHints)

   defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
   if bestHint.NUMANodeAffinity.IsEqual(defaultAffinity) {
      bestHint = TopologyHint{nil, bestHint.Preferred}
   }

   admit := p.canAdmitPodResult(&bestHint)
   return bestHint, admit
}
複製代碼

從上述三種分配策略,能夠發現Merge方法的一些相似流程:

1. filterProvidersHints
2. mergeFilteredHints
3. canAdmitPodResult
複製代碼

其中filterProvidersHints位於pkg/kubelet/cm/topologymanager/policy.go:62

func filterProvidersHints(providersHints []map[string][]TopologyHint) [][]TopologyHint {
   // Loop through all hint providers and save an accumulated list of the
   // hints returned by each hint provider. If no hints are provided, assume
   // that provider has no preference for topology-aware allocation.
   var allProviderHints [][]TopologyHint
   for _, hints := range providersHints {
      // If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
      if len(hints) == 0 {
         klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
         allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
         continue
      }

      // Otherwise, accumulate the hints for each resource type into allProviderHints.
      for resource := range hints {
         if hints[resource] == nil {
            klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
            allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
            continue
         }

         if len(hints[resource]) == 0 {
            klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
            allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
            continue
         }

         allProviderHints = append(allProviderHints, hints[resource])
      }
   }
   return allProviderHints
}
複製代碼

遍歷全部的HintProviders,收集並存儲hint。若是HintProviders沒有提供任何hint,那麼就默認爲該provider沒有任何資源分配。最終返回allProviderHints.

其中mergeFilteredHints位於pkg/kubelet/cm/topologymanager/policy.go:95

// Merge a TopologyHints permutation to a single hint by performing a bitwise-AND
// of their affinity masks. The hint shall be preferred if all hits in the permutation
// are preferred.
func mergePermutation(numaNodes []int, permutation []TopologyHint) TopologyHint {
	// Get the NUMANodeAffinity from each hint in the permutation and see if any
	// of them encode unpreferred allocations.
	preferred := true
	defaultAffinity, _ := bitmask.NewBitMask(numaNodes...)
	var numaAffinities []bitmask.BitMask
	for _, hint := range permutation {
		// Only consider hints that have an actual NUMANodeAffinity set.
		if hint.NUMANodeAffinity == nil {
			numaAffinities = append(numaAffinities, defaultAffinity)
		} else {
			numaAffinities = append(numaAffinities, hint.NUMANodeAffinity)
		}

		if !hint.Preferred {
			preferred = false
		}
	}

	// Merge the affinities using a bitwise-and operation.
	mergedAffinity := bitmask.And(defaultAffinity, numaAffinities...)
	// Build a mergedHint from the merged affinity mask, indicating if an
	// preferred allocation was used to generate the affinity mask or not.
	return TopologyHint{mergedAffinity, preferred}
}


func mergeFilteredHints(numaNodes []int, filteredHints [][]TopologyHint) TopologyHint {
   // Set the default affinity as an any-numa affinity containing the list
   // of NUMA Nodes available on this machine.
   defaultAffinity, _ := bitmask.NewBitMask(numaNodes...)

   // Set the bestHint to return from this function as {nil false}.
   // This will only be returned if no better hint can be found when
   // merging hints from each hint provider.
   bestHint := TopologyHint{defaultAffinity, false}
   iterateAllProviderTopologyHints(filteredHints, func(permutation []TopologyHint) {
      // Get the NUMANodeAffinity from each hint in the permutation and see if any
      // of them encode unpreferred allocations.
      mergedHint := mergePermutation(numaNodes, permutation)
      // Only consider mergedHints that result in a NUMANodeAffinity > 0 to
      // replace the current bestHint.
      if mergedHint.NUMANodeAffinity.Count() == 0 {
         return
      }

      // If the current bestHint is non-preferred and the new mergedHint is
      // preferred, always choose the preferred hint over the non-preferred one.
      if mergedHint.Preferred && !bestHint.Preferred {
         bestHint = mergedHint
         return
      }

      // If the current bestHint is preferred and the new mergedHint is
      // non-preferred, never update bestHint, regardless of mergedHint's
      // narowness.
      if !mergedHint.Preferred && bestHint.Preferred {
         return
      }

      // If mergedHint and bestHint has the same preference, only consider
      // mergedHints that have a narrower NUMANodeAffinity than the
      // NUMANodeAffinity in the current bestHint.
      if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
         return
      }

      // In all other cases, update bestHint to the current mergedHint
      bestHint = mergedHint
   })

   return bestHint
}
複製代碼

mergeFilteredHints函數處理流程以下所示:

  1. 經過cadvisor傳遞的NUMA節點數生成bitmask
  2. 設置 bestHint := TopologyHint{defaultAffinity, false}若是沒有符合條件的hint,返回該hint
  3. 取每種資源類型生成的TopologyHints的交叉積
  4. 對於交叉中的每一個條目,每一個TopologyHint的NUMA親和力執行位計算。 在合併hint中將此設置爲NUMA親和性。
  5. 若是條目中的全部hint都將Preferred設置爲True,則在合併hint中的Preferred設置爲True。
  6. 若是條目中存在Preferred設置爲False的hint,則在合併hint中的Preferred設置爲False。 若是其NUMA親和性節點數量全爲0,則在合併hint中的Preferred設置爲False。

接上文的分配說明,Container0的hint爲:

cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{01: True}, {10: True}}
nic-vendor.com/nic: {{01: True}, {10: True}}
複製代碼

上面的算法將產生的交叉積及合併後的hint:

cross-product entry{cpu, gpu-vendor.com/gpu, nic-vendor.com/nic} "merged" hint {{01: True}, {01: True}, {01: True}} {01: True}
{{01: True}, {01: True}, {10: True}} {00: False}
{{01: True}, {10: True}, {01: True}} {00: False}
{{01: True}, {10: True}, {10: True}} {00: False}

{{10: True}, {01: True}, {01: True}} {00: False}
{{10: True}, {01: True}, {10: True}} {00: False}
{{10: True}, {10: True}, {01: True}} {00: False}
{{10: True}, {10: True}, {10: True}} {01: True}

{{11: False}, {01: True}, {01: True}} {01: False}
{{11: False}, {01: True}, {10: True}} {00: False}
{{11: False}, {10: True}, {01: True}} {00: False}
{{11: False}, {10: True}, {10: True}} {10: False}

生成合並的hint列表以後,將根據Kubelet配置的拓撲管理器分配策略來肯定哪一個爲最佳hint。

通常流程以下所示:

  1. 根據合併hint的「狹窄度」進行排序。狹窄度定義爲hint的NUMA類似性掩碼中設置的位數。設置的位數越少,hint越窄。對於在NUMA關聯掩碼中設置了相同位數的hint,設置爲最低位的hint被認爲是較窄的。
  2. 根據合併hint的Preferred字段排序。Preferred爲true的hint優於Preferred爲true的hint。
  3. 爲Preferred選擇具備最佳設置的最窄hint。

在上面的示例中,當前支持的全部策略都將使用hint{01:True}以准入該Pod。


4、後續發展

4.1 已知問題

  1. 拓撲管理器所能處理的最大 NUMA 節點個數是 8。若 NUMA 節點數超過 8, 枚舉可能的 NUMA 親和性而生成hint時會致使數據爆炸式增加。
  2. 調度器不支持資源拓撲功能,當調度至該節點,但由於拓撲管理器的緣由致使在該節點上調度失敗。

4.2 功能特性

a. hugepage的numa應用

如前所述,當前僅可用於TopologyManager的三個HintProvider是CPUManager、MemoryManager及DeviceManager。 可是,目前也正在努力增長對hugepage的支持,TopologyManager最終將可以在同一NUMA節點上分配內存,大頁,CPU和PCI設備。

b. 調度

當前,TopologyManager不參與Pod調度決策,僅充當Pod Admission控制器,當調度器將Pod調度到某節點後,TopologyManager才斷定應該接受仍是拒絕該pod。可是可能會由於節點可用的NUMA對齊資源而拒絕pod,這跟調度系統的決定相悖。

那麼咱們如何解決這個問題呢?當前Kubernetes調度框架提供實現framework架構,調度算法插件化,能夠實現諸如NUMA對齊之類的調度插件。

d. Pod對齊策略

如前所述,單個策略經過Kubelet命令行應用於節點上的全部Pod,而不是根據Pod進行自定義配置。

當前實現該特性最大的問題是,此功能須要更改API才能在Pod結構或其關聯的RuntimeClass中表達所需的對齊策略。

後續相關內容,請查看公衆號:DCOS


5、參考資料

一、kubernetes-1-18-feature-topoloy-manager-beta

二、topology manager

三、cpu manager policy

四、設計文檔

相關文章
相關標籤/搜索