Evented PLEG: Evented PLEG: iSulad 稳态 CPU 利用率降低30%的关键特性

openEuler2024-06-27openEuler

背景

容器技术在不断发展的过程中,已被广泛应用于多种场景。openEuler 社区容器引擎项目 iSulad[1]面向 CT、IT 领域的不同需求而生,它具有轻量级、高性能的特点,可以在资源受限的环境中运行,如边缘计算和 IoT 场景,并始终在提高容器运行效率、降低容器运行底噪开销等问题上进行着不断地尝试与探索。

iSulad 向北支持 CRI 接口,对接 Kubernetes,并始终紧跟上游社区,提供最新的生态支持。

在 openEuler 23.09中,iSulad 引入Sandbox语义[2]用于支持Kuasar,用户能够使用 Sandbox API 管理沙箱,将沙箱管理与容器管理解耦,简化调用链,提高了容器引擎的性能和稳定性。

基于 Sandbox API,在 open Euler 24.03 LTS 中,iSulad开始提供对普通容器 CRI V1 接口的支持,并将 CRI 接口更新至1.29[3],为 iSulad 的性能提升提供了新的优化空间,而其中性能提升的关键特性就在于 EventedPLEG。

Pod 生命周期管理事件

概述

Kubelet 作为每个节点的守护进程,在管理节点中的 Pod 时,需要获取所有容器的最新状态,PLEG(Pod Lifecycle Event Generator)负责为 Kubelet 生成容器运行时的 Pod 生命周期事件,从而执行相应控制逻辑并驱动Pod状态以匹配Pod规格。

Generic PLEG

Kubelet 在1.26之前,会通过 Generic PLEG 定期查询容器运行时,调用 CRI 的 ListPodSandbox 和ListContainers 接口,获取 Pod 和容器的信息,更新到缓存中,并组装成事件发送至Kubelt的PLEG Channel。

然而随着 Pod 和容器数量的不断增加,轮询会产生不可忽略的开销,定期、并发、大量的请求会造成 CPU 利用率飙升,影响性能,并且可能会导致容器运行时不堪重负从而带来可靠性问题。

Evented PLEG

为减少稳态状态下轮询造成的开销,KEP-3386[4]提出 Evented PLEG,Kubelet 通过监听来自 CRI 实现的 gRPC 服务器流事件,试图减少容器在没有规格、状态变化时的不必要轮询工作。通过减少对容器状态的频繁轮询,降低 Kubelet、容器运行时稳态状态下的 CPU 利用率。

Evented PLEG 解决方案

社区方案

service RuntimeService {
    ...
    // GetContainerEvents gets container events from the CRI runtime
    rpc GetContainerEvents(GetEventsRequest) returns (stream ContainerEventResponse) {}
}

message GetEventsRequest {}

message ContainerEventResponse {
    // ID of the container
    string container_id = 1;
    // Type of the container event
    ContainerEventType container_event_type = 2;
    // Creation timestamp of this event
    int64 created_at = 3;
    // Sandbox status
    PodSandboxStatus pod_sandbox_status = 4;
    // Container statuses
    repeated ContainerStatus containers_statuses = 5;
}

enum ContainerEventType {
    // Container created
    CONTAINER_CREATED_EVENT = 0;
    // Container started
    CONTAINER_STARTED_EVENT = 1;
    // Container stopped
    CONTAINER_STOPPED_EVENT = 2;
    // Container deleted
    CONTAINER_DELETED_EVENT = 3;
}

为减少稳态状态下轮询造成的开销,Kubernets 新增如上所述的 CRI 接口,通过 GetContainerEvents 作为与 CRI 运行时的长连接,Kubelet 能够监听来自 CRI 实现的 gRPC 服务器流事件, CRI 运行时从而能够提供一种当容器状态发生改变时通知Kubelet的方式。

Kubelet 获取容器状态发生变化时的事件,对应 ContainerEventType 定义的四种类型:

  • 容器创建
  • 容器启动
  • 容器停止
  • 容器删除

生成的事件中包含了对应事件类型、容器 ID、事件发生时间戳、 容器所对应的 Pod 状态 PodSandboxStatus 和 Pod 中所包含所有的容器状态的 ContainerStatus。

Kubelet Evented PLEG 机制

Evented PLEG 能够减少稳态情况(没有容器规格、状态变化)下的轮询频率,而不主张完全去除轮询,原因在于 gRPC 连接错误等异常情况可能造成事件的缺失。

Evented PLEG 开启后,Kubeltet 的 Pod 状态来源有两个,通过列举实现的 Generic PLEG 和通过事件流实现的Evented PLEG。

为防止 Generic PLEG 与 Evented PLEG 状态信息的竞争,开启 Evented PLEG 后,Generic PLEG 应该依赖 CRI 接口 PodSandboxStatus 直接获取Pod状态信息,Generic PLEG 和 Evented PLEG 获取的 Pod 状态的时间戳信息应该来自 CRI 运行时,从而能够更加接近实际的 Pod 状态的真实时间。

如图所示,Kubelet 从而能够根据时间戳信息确定最新的 Pod 状态并缓存,防止旧的 Pod 状态缓存覆盖新的状态信息。

sequenceDiagram
    Title: Modified Cache Setter
    Evented PLEG->>Cache: Set PodStatus
    Generic PLEG->>Cache: Set PodStatus
    Note over  Cache: Update the PodStatus only if it is newer than Cache

image2

图1 Kubelet Modified Cache Setter

iSulad 实现与效果

iSulad 的 Evented PLEG 实现采用了发布者-订阅者模式,每一次 CRI rpc 接口 GetContainerEvents 的调用作为一个订阅者,该接口调用可以来自 Kubelet 或者 crictl 调试工具,当 iSulad 监控到 Pod、容器生命周期的变化时,会生成对应的事件广播至所有的订阅者。

image2

图2 iSulad Evented PLEG 设计图

在实现上 iSulad 新增 mailbox 模块,提供发布者-订阅者模式支持。每一个 GetContainerEvents CRI rpc 接口调用会通过 mailbox_subscribe 函数进行事件订阅,在容器或者Pod生命周期状态发生变化时,iSulad的 sandbox 模块和容器运行时模块调用 maibox_publish,生成对应的 CRI Container Event,添加至 mailbox 模块中的消息队列中,最终由该消息队列广播至所有的订阅者,订阅者从而将收到的消息发送至 Kubelet 或 crictl 调试工具。

下表给出了开启 Evented PLEG 后 iSulad 和 Kubelet 在不同 busybox 容器数目下稳态 CPU 利用率所减少的值,可以看到稳态情况下为 iSulad 平均带来30%左右的性能提升,为 Kubelet 带来10%左右的性能提升。

busybox 容器数iSuladKubelet
1030.5%11.0%
5027.5%10.4%
10028.5%10.1%

表1 iSulad、Kubelet Evented PLEG 性能提升

总结

此次 CRI V1 的升级为 iSulad 引进了上游社区最新的特性,同时还为 iSulad 稳态情况下带来了30%左右的性能提升。iSulad 在演进过程中始终紧跟上游生态,提供最新的社区支持,并且不断在提高容器运行效率、降低容器运行底噪开销等问题上探索新的方向。

文中所述的特性支持,由 iSulad SIG 参与,相关源码均已在 openEuler 社区开源。如果您对相关技术感兴趣,欢迎您的围观和加入。您可以添加小助手微信,加入对应 SIG 微信群。您可以添加小助手微信,加入对应 SIG 微信群。

image2

参考

[1] iSulad,https://gitee.com/openeuler/iSulad

[2] iSulad Sandbox API:简化调用链,可靠性倍增, https://mp.weixin.qq.com/s?__biz=MzkyMjYzNjU0Ng==&mid=2247507591&idx=1&sn=267e5ec03dfbc311e76b882cd458ea29&source=41#wechat_redirect

[3] CRI v1.29,https://github.com/kubernetes/cri-api/tree/kubernetes-1.29.0

[4] KEP-3386: Kubelet Evented PLEG for Better Performance,https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/3386-kubelet-evented-pleg/README.md


【免责声明】本文仅代表作者本人观点,与本网站无关。本网站对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文仅供读者参考,由此产生的所有法律责任均由读者本人承担。