自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

淺析 Kubelet 驅(qū)逐機制

開發(fā) 前端
本文主要分析了 Kubelet 的 Eviction Manager,包括其對 Linux CGroup 事件的監(jiān)聽、判斷 Pod 驅(qū)逐的優(yōu)先級等。了解了這些之后,我們就可以根據(jù)自身應用的重要性來設置優(yōu)先級,甚至設置成 Critical Pod。

 [[420290]]

Kubelet 出于對節(jié)點的保護,允許在節(jié)點資源不足的情況下,開啟對節(jié)點上 Pod 進行驅(qū)逐的功能。最近對 Kubelet 的驅(qū)逐機制有所研究,發(fā)現(xiàn)其中有很多值得學習的地方,總結(jié)下來和大家分享。

Kubelet 的配置

Kubelet 的驅(qū)逐功能需要在配置中打開,并且配置驅(qū)逐的閾值。Kubelet 的配置中與驅(qū)逐相關(guān)的參數(shù)如下:

  1. type KubeletConfiguration struct { 
  2.     ... 
  3.   // Map of signal names to quantities that defines hard eviction thresholds. For example: {"memory.available""300Mi"}. 
  4.   EvictionHard map[string]string 
  5.   // Map of signal names to quantities that defines soft eviction thresholds.  For example: {"memory.available""300Mi"}. 
  6.   EvictionSoft map[string]string 
  7.   // Map of signal names to quantities that defines grace periods for each soft eviction signal. For example: {"memory.available""30s"}. 
  8.   EvictionSoftGracePeriod map[string]string 
  9.   // Duration for which the kubelet has to wait before transitioning out of an eviction pressure condition. 
  10.   EvictionPressureTransitionPeriod metav1.Duration 
  11.   // Maximum allowed grace period (in seconds) to use when terminating pods in response to a soft eviction threshold being met. 
  12.   EvictionMaxPodGracePeriod int32 
  13.   // Map of signal names to quantities that defines minimum reclaims, which describe the minimum 
  14.   // amount of a given resource the kubelet will reclaim when performing a pod eviction while 
  15.   // that resource is under pressure. For example: {"imagefs.available""2Gi"
  16.   EvictionMinimumReclaim map[string]string 
  17.   ... 

其中,EvictionHard 表示硬驅(qū)逐,一旦達到閾值,就直接驅(qū)逐;EvictionSoft 表示軟驅(qū)逐,即可以設置軟驅(qū)逐周期,只有超過軟驅(qū)逐周期后,才啟動驅(qū)逐,周期用 EvictionSoftGracePeriod 設置;EvictionMinimumReclaim 表示設置最小可用的閾值,比如 imagefs。

可以設置的驅(qū)逐信號有:

  • memory.available:node.status.capacity[memory] - node.stats.memory.workingSet,節(jié)點可用內(nèi)存
  • nodefs.available:node.stats.fs.available,Kubelet 使用的文件系統(tǒng)的可使用容量大小
  • nodefs.inodesFree:node.stats.fs.inodesFree,Kubelet 使用的文件系統(tǒng)的可使用 inodes 數(shù)量
  • imagefs.available:node.stats.runtime.imagefs.available,容器運行時用來存放鏡像及容器可寫層的文件系統(tǒng)的可使用容量
  • imagefs.inodesFree:node.stats.runtime.imagefs.inodesFree,容器運行時用來存放鏡像及容器可寫層的文件系統(tǒng)的可使用 inodes 容量
  • allocatableMemory.available:留給分配 Pod 用的可用內(nèi)存
  • pid.available:node.stats.rlimit.maxpid - node.stats.rlimit.curproc,留給分配 Pod 用的可用 PID

Eviction Manager 工作原理

Eviction Manager的主要工作在 synchronize 函數(shù)里。有兩個地方觸發(fā) synchronize 任務,一個是 monitor 任務,每 10s 觸發(fā)一次;另一個是根據(jù)用戶配置的驅(qū)逐信號,啟動的 notifier 任務,用來監(jiān)聽內(nèi)核事件。

notifier

notifier 由 eviction manager 中的 thresholdNotifier 啟動,用戶配置的每一個驅(qū)逐信號,都對應一個 thresholdNotifier,而 thresholdNotifier 和 notifier 通過 channel 通信,當 notifier 向 channel 中發(fā)送消息時,對應的 thresholdNotifier 便觸發(fā)一次 synchronize 邏輯。

notifier 采用的是內(nèi)核的 cgroups Memory thresholds,cgroups 允許用戶態(tài)進程通過 eventfd 來設置當 memory.usage_in_bytes 達到某閾值時,內(nèi)核給應用發(fā)送通知。具體做法是向 cgroup.event_control 寫入 " "。

notifier 的初始化代碼如下(為了方便閱讀,刪除了部分不相干代碼),主要是找到 memory.usage_in_bytes 的文件描述符 watchfd,cgroup.event_control 的文件描述符 controlfd,完成 cgroup memory thrsholds 的注冊。

  1. func NewCgroupNotifier(path, attribute string, threshold int64) (CgroupNotifier, error) { 
  2.   var watchfd, eventfd, epfd, controlfd int 
  3.  
  4.   watchfd, err = unix.Open(fmt.Sprintf("%s/%s", path, attribute), unix.O_RDONLY|unix.O_CLOEXEC, 0) 
  5.   defer unix.Close(watchfd) 
  6.    
  7.   controlfd, err = unix.Open(fmt.Sprintf("%s/cgroup.event_control", path), unix.O_WRONLY|unix.O_CLOEXEC, 0) 
  8.   defer unix.Close(controlfd) 
  9.    
  10.   eventfd, err = unix.Eventfd(0, unix.EFD_CLOEXEC) 
  11.   defer func() { 
  12.     // Close eventfd if we get an error later in initialization 
  13.     if err != nil { 
  14.       unix.Close(eventfd) 
  15.     } 
  16.   }() 
  17.    
  18.   epfd, err = unix.EpollCreate1(unix.EPOLL_CLOEXEC) 
  19.   defer func() { 
  20.     // Close epfd if we get an error later in initialization 
  21.     if err != nil { 
  22.       unix.Close(epfd) 
  23.     } 
  24.   }() 
  25.    
  26.   config := fmt.Sprintf("%d %d %d", eventfd, watchfd, threshold) 
  27.   _, err = unix.Write(controlfd, []byte(config)) 
  28.  
  29.   return &linuxCgroupNotifier{ 
  30.     eventfd: eventfd, 
  31.     epfd:    epfd, 
  32.     stop:    make(chan struct{}), 
  33.   }, nil 

notifier 在啟動時還會通過 epoll 來監(jiān)聽上述的 eventfd,當監(jiān)聽到內(nèi)核發(fā)送的事件時,說明使用的內(nèi)存已超過閾值,便向 channel 中發(fā)送信號。

  1. func (n *linuxCgroupNotifier) Start(eventCh chan<- struct{}) { 
  2.   err := unix.EpollCtl(n.epfd, unix.EPOLL_CTL_ADD, n.eventfd, &unix.EpollEvent{ 
  3.     Fd:     int32(n.eventfd), 
  4.     Events: unix.EPOLLIN, 
  5.   }) 
  6.  
  7.   for { 
  8.     select { 
  9.     case <-n.stop: 
  10.       return 
  11.     default
  12.     } 
  13.     event, err := wait(n.epfd, n.eventfd, notifierRefreshInterval) 
  14.     if err != nil { 
  15.       klog.InfoS("Eviction manager: error while waiting for memcg events""err", err) 
  16.       return 
  17.     } else if !event { 
  18.       // Timeout on wait.  This is expected if the threshold was not crossed 
  19.       continue 
  20.     } 
  21.     // Consume the event from the eventfd 
  22.     buf := make([]byte, eventSize) 
  23.     _, err = unix.Read(n.eventfd, buf) 
  24.     if err != nil { 
  25.       klog.InfoS("Eviction manager: error reading memcg events""err", err) 
  26.       return 
  27.     } 
  28.     eventCh <- struct{}{} 
  29.   } 

synchronize 邏輯每次執(zhí)行都會判斷 10s 內(nèi) notifier 是否有更新,并重新啟動 notifier。cgroup memory threshold 的計算方式為內(nèi)存總量減去用戶設置的驅(qū)逐閾值。

synchronize

Eviction Manager 的主邏輯 synchronize 細節(jié)比較多,這里就不貼源碼了,梳理下來主要是以下幾個事項:

  1. 針對每個信號構(gòu)建排序函數(shù);
  2. 更新 threshold 并重新啟動 notifier;
  3. 獲取當前節(jié)點的資源使用情況(cgroup 的信息)和所有活躍的 pod;
  4. 針對每個信號,分別確定當前節(jié)點的資源使用情況是否達到驅(qū)逐的閾值,如果都沒有,則退出當前循環(huán);
  5. 將所有的信號進行優(yōu)先級排序,優(yōu)先級為:跟內(nèi)存有關(guān)的信號先進行驅(qū)逐;
  6. 向 apiserver 發(fā)送 驅(qū)逐事件;
  7. 將所有活躍的 pod 進行優(yōu)先級排序;
  8. 按照排序后的順序?qū)?pod 進行驅(qū)逐。

計算驅(qū)逐順序

對 pod 的驅(qū)逐順序主要取決于三個因素:

  • pod 的資源使用情況是否超過其 requests;
  • pod 的 priority 值;
  • pod 的內(nèi)存使用情況;

三個因素的判斷順序也是根據(jù)注冊進 orderedBy 的順序。這里 orderedBy 函數(shù)的多級排序也是 Kubernetes 里一個值得學習(抄作業(yè))的一個實現(xiàn),感興趣的讀者可以自行查閱源碼。

  1. // rankMemoryPressure orders the input pods for eviction in response to memory pressure. 
  2. // It ranks by whether or not the pod's usage exceeds its requests, then by priority, and 
  3. // finally by memory usage above requests. 
  4. func rankMemoryPressure(pods []*v1.Pod, stats statsFunc) { 
  5.   orderedBy(exceedMemoryRequests(stats), priority, memory(stats)).Sort(pods) 

驅(qū)逐 Pod

接下來就是驅(qū)逐 Pod 的實現(xiàn)。Eviction Manager 驅(qū)逐 Pod 就是干凈利落的 kill,里面具體的實現(xiàn)這里不展開分析,值得注意的是在驅(qū)逐之前有一個判斷,如果 IsCriticalPod 返回為 true 則不驅(qū)逐。

  1. func (m *managerImpl) evictPod(pod *v1.Pod, gracePeriodOverride int64, evictMsg string, annotations map[string]string) bool { 
  2.   // If the pod is marked as critical and staticand support for critical pod annotations is enabled, 
  3.   // do not evict such pods. Static pods are not re-admitted after evictions. 
  4.   // https://github.com/kubernetes/kubernetes/issues/40573 has more details. 
  5.   if kubelettypes.IsCriticalPod(pod) { 
  6.     klog.ErrorS(nil, "Eviction manager: cannot evict a critical pod""pod", klog.KObj(pod)) 
  7.     return false 
  8.   } 
  9.   // record that we are evicting the pod 
  10.   m.recorder.AnnotatedEventf(pod, annotations, v1.EventTypeWarning, Reason, evictMsg) 
  11.   // this is a blocking call and should only return when the pod and its containers are killed. 
  12.   klog.V(3).InfoS("Evicting pod""pod", klog.KObj(pod), "podUID", pod.UID, "message", evictMsg) 
  13.   err := m.killPodFunc(pod, true, &gracePeriodOverride, func(status *v1.PodStatus) { 
  14.     status.Phase = v1.PodFailed 
  15.     status.Reason = Reason 
  16.     status.Message = evictMsg 
  17.   }) 
  18.   if err != nil { 
  19.     klog.ErrorS(err, "Eviction manager: pod failed to evict""pod", klog.KObj(pod)) 
  20.   } else { 
  21.     klog.InfoS("Eviction manager: pod is evicted successfully""pod", klog.KObj(pod)) 
  22.   } 
  23.   return true 

再看看 IsCriticalPod 的代碼:

  1. func IsCriticalPod(pod *v1.Pod) bool { 
  2.   if IsStaticPod(pod) { 
  3.     return true 
  4.   } 
  5.   if IsMirrorPod(pod) { 
  6.     return true 
  7.   } 
  8.   if pod.Spec.Priority != nil && IsCriticalPodBasedOnPriority(*pod.Spec.Priority) { 
  9.     return true 
  10.   } 
  11.   return false 
  12.  
  13. // IsMirrorPod returns true if the passed Pod is a Mirror Pod. 
  14. func IsMirrorPod(pod *v1.Pod) bool { 
  15.   _, ok := pod.Annotations[ConfigMirrorAnnotationKey] 
  16.   return ok 
  17.  
  18. // IsStaticPod returns true if the pod is a static pod. 
  19. func IsStaticPod(pod *v1.Pod) bool { 
  20.   source, err := GetPodSource(pod) 
  21.   return err == nil && source != ApiserverSource 
  22.  
  23. func IsCriticalPodBasedOnPriority(priority int32) bool { 
  24.   return priority >= scheduling.SystemCriticalPriority 

從代碼看,如果 Pod 是 Static、Mirror、Critical Pod 都不驅(qū)逐。其中 Static 和 Mirror 都是從 Pod 的 annotation 中判斷;而 Critical 則是通過 Pod 的 Priority 值判斷的,如果 Priority 為 system-cluster-critical/system-node-critical 都屬于 Critical Pod。

不過這里值得注意的是,官方文檔里提及 Critical Pod 是說,如果非 Static Pod 被標記為 Critical,并不完全保證不會被驅(qū)逐:https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods 。因此,很有可能是社區(qū)并沒有想清楚這種情況是否要驅(qū)逐,并不排除后面會改變這段邏輯,不過也有可能是文檔沒有及時更新??。

總結(jié)

本文主要分析了 Kubelet 的 Eviction Manager,包括其對 Linux CGroup 事件的監(jiān)聽、判斷 Pod 驅(qū)逐的優(yōu)先級等。了解了這些之后,我們就可以根據(jù)自身應用的重要性來設置優(yōu)先級,甚至設置成 Critical Pod。

責任編輯:武曉燕 來源: CS實驗室
相關(guān)推薦

2017-04-12 11:46:46

前端瀏覽器渲染機制

2009-06-11 17:03:29

Java線程

2009-06-23 14:15:00

Java垃圾回收

2022-06-01 16:01:58

MySQL內(nèi)存管理系統(tǒng)

2011-05-19 10:57:45

DNSSEC密鑰加密

2009-08-03 18:35:51

ASP.NET數(shù)據(jù)緩存

2011-09-01 17:46:22

MySQL ProxyLua腳本

2016-01-08 10:06:52

2023-02-09 16:47:34

KubernetesPod優(yōu)先級

2016-09-29 22:54:55

2023-07-07 10:41:00

Javajar文件

2016-08-23 14:25:19

MySQL約束數(shù)據(jù)庫

2010-06-07 13:30:15

2009-04-08 09:58:07

ASP.NET MVCTempData框架

2009-12-29 09:53:25

NHibernate緩

2024-07-17 09:23:58

Vite插件機制

2009-08-10 14:38:29

ASP.NET組件設計

2018-08-20 16:00:23

MySQL并發(fā)控制MVCC

2024-10-08 10:13:17

2023-03-17 08:04:15

云存儲安全Veritas
點贊
收藏

51CTO技術(shù)棧公眾號