边缘计算到端侧AI框架的演化(三) EasyFaas推荐容器资源的动态合并

60 阅读3分钟

背景

在边缘计算的场景中,边缘端的资源非常紧张,需要将已经申请的空闲容器做合并。而easyfaas刚好就提供了这一功能

sequenceDiagram  
    participant Controller as "控制器"  
    participant RuntimeManager as "运行时管理器"  
    participant Funclet as "Funclet"  
    participant Container as "容器"  
  
    Note over Controller,Container: 容器列表获取流程  
    Controller->>Funclet: List(criteria)  
    Funclet->>RuntimeManager: ListAllContainers()  
    RuntimeManager->>Container: 获取容器状态  
    Container-->>RuntimeManager: 返回容器信息  
    RuntimeManager-->>Funclet: 返回容器列表  
    Funclet-->>Controller: 返回推荐容器列表  
  
    Note over Controller,Container: 扩容推荐流程  
    Controller->>RuntimeManager: OccupyColdRuntime(request)  
    RuntimeManager->>RuntimeManager: 检查资源需求  
    alt 需要扩容  
        RuntimeManager->>RuntimeManager: 计算合并容器数量  
        RuntimeManager->>Container: 标记目标容器  
        RuntimeManager->>Container: 合并其他容器  
        RuntimeManager-->>Controller: 返回ScaleUpRecommendation  
        Controller->>Funclet: WarmUp(recommendation)  
        Funclet->>Container: 执行扩容操作  
    else 无需扩容  
        RuntimeManager-->>Controller: 返回运行时信息  
    end  
  
    Note over Controller,Container: 缩容推荐流程  
    Controller->>RuntimeManager: CoolDownRuntime(runtime)  
    RuntimeManager->>RuntimeManager: 检查闲置时间  
    alt 需要缩容  
        RuntimeManager->>RuntimeManager: 计算重置容器数量  
        RuntimeManager->>Container: 标记重置容器  
        RuntimeManager-->>Controller: 返回ScaleDownRecommendation  
        Controller->>Funclet: Reset(recommendation)  
        Funclet->>Container: 执行缩容操作  
    else 无需缩容  
        RuntimeManager-->>Controller: 无推荐  
    end

详细资源合并流程:

sequenceDiagram  
    participant User as 用户请求  
    participant Controller as Controller  
    participant RuntimeManager as RuntimeManager  
    participant Funclet as Funclet  
    participant CgroupManager as CgroupManager  
    participant Container as 容器  
  
    User->>Controller: 函数调用请求  
    Controller->>RuntimeManager: OccupyColdRuntime(req)  
      
    Note over RuntimeManager: 1. 资源需求检测  
    RuntimeManager->>RuntimeManager: functionMemorySizeToBytes()  
    RuntimeManager->>RuntimeManager: checkAndMarkResource(memBytes)  
      
    alt 资源不足  
        RuntimeManager-->>Controller: 返回 nil, nil  
        Controller-->>User: 资源不足错误  
    else 资源充足  
        RuntimeManager->>RuntimeManager: isNeedScale(memBytes)  
          
        alt 不需要扩容  
            RuntimeManager->>RuntimeManager: 遍历rtArray寻找可用容器  
            RuntimeManager->>RuntimeManager: rt.CAS(OpOccupy, input)  
            RuntimeManager-->>Controller: 返回 RuntimeInfo, nil  
        else 需要扩容  
            Note over RuntimeManager: 2. 生成扩容推荐  
            RuntimeManager->>RuntimeManager: occupyColdWithScaleUpRecommendation()  
            RuntimeManager->>RuntimeManager: 计算scaleCount  
            RuntimeManager->>RuntimeManager: 选择目标容器和待合并容器  
            RuntimeManager-->>Controller: 返回 RuntimeInfo, ScaleUpRecommendation  
              
            Note over Controller,Funclet: 3. 执行扩容操作  
            Controller->>Funclet: 发送扩容推荐  
              
            loop 处理被合并容器  
                Funclet->>Funclet: FrozenContainer(id)  
                Funclet->>Funclet: scaleDownContainerToMinimum(id)  
                Funclet->>CgroupManager: UpdateContainerResource()  
                CgroupManager->>Container: 更新cgroup限制  
            end  
              
            Note over Funclet: 4. 目标容器扩容  
            Funclet->>Funclet: GetResourceConfigByReadableMemory()  
            Funclet->>Funclet: scaleUpContainer()  
            Funclet->>CgroupManager: UpdateContainerResource()  
            CgroupManager->>Container: 更新cgroup限制  
              
            Funclet-->>Controller: 扩容完成  
        end  
    end  
      
    Controller->>Container: 执行函数  
    Container-->>Controller: 返回结果  
    Controller-->>User: 返回执行结果  
      
    Note over Controller,Funclet: 5. 资源同步监控  
    loop 定期任务  
        Controller->>Funclet: NodeInfo()  
        Controller->>RuntimeManager: SyncResource()  
        Controller->>Funclet: List()  
        Controller->>RuntimeManager: SyncRuntimeResource()  
    end  
  1. 资源需求检测

当函数调用到达时,系统首先在OccupyColdRuntime中检测是否需要扩容: runtime_dispatcher.go:187-222

这里的关键逻辑是isNeedScale(memBytes)函数,它通过比较请求内存与基础内存来判断是否需要扩容。

  1. 资源可用性检查

在分配资源前,系统会通过checkAndMarkResource检查可用资源: runtime_dispatcher.go:378-390

这个函数使用读写锁确保线程安全,先检查可分配内存是否足够,然后标记即将使用的资源。

  1. 扩容推荐生成

当需要扩容时,系统调用occupyColdWithScaleUpRecommendation生成扩容方案: runtime_dispatcher.go:225-276

这个函数的核心逻辑包括:

● 计算需要合并的容器数量:scaleCount = ceil(memBytes/BaseMemory) - 1

● 选择目标容器和待合并容器

● 生成ScaleUpRecommendation结构

● 当有函数调用请求时,系统会通过 tryGetRuntime 方法获取运行时容器 invoke.go:363-409 。

2. 检查是否需要扩容

在 OccupyColdRuntime 方法中,系统会检查当前请求的内存需求是否需要扩容 runtime_dispatcher.go:211-222 。

关键判断逻辑:

● 如果 needScale 为 false,直接分配普通容器

● 如果 needScale 为 true,调用 occupyColdWithScaleUpRecommendation 生成扩容推荐

3. 扩容推荐的生成条件

扩容推荐会在以下情况生成:

● 函数的内存需求超过基础内存大小 (BaseMemory)

● 需要合并多个容器来满足内存要求

● 系统计算出需要的容器数量:scaleCount = ceil(memBytes/BaseMemory) - 1

4. 自动执行扩容

生成的扩容推荐会自动传递给 Funclet 的 WarmUp 方法执行 invoke.go:390-394 。

实际触发方式

要触发扩容推荐机制,你需要:

1.  调用内存需求较大的函数:确保函数配置的内存大小超过系统的基础内存配置

2.  在冷启动场景下调用:当没有可用的热容器时,系统会尝试占用冷容器并可能触发扩容

3.  确保有足够的可用容器:系统需要有足够的容器可以进行合并操作

扩容推荐的数据结构

扩容推荐使用 ScaleUpRecommendation 结构体定义: controller.go:224-228

这个结构包含三个关键字段:

● TargetMemory: 目标内存大小(字符串格式)

● TargetContainer: 目标容器ID

● MergedContainers: 需要合并的容器ID列表

实际生成过程

在 occupyColdWithScaleUpRecommendation 函数中,系统按以下步骤填充推荐列表: runtime_dispatcher.go:227-248

1.  选择目标容器:系统遍历可用容器,选择第一个成功占用的容器作为 TargetContainer

2.  设置目标内存:将请求的内存大小转换为可读格式设置为 TargetMemory

3.  计算需要合并的容器数量:scaleCount = ceil(memBytes/BaseMemory) - 1 runtime_dispatcher.go:254-267

4.  选择合并容器:系统继续遍历容器数组,将成功标记为 OpMerged 状态的容器ID添加到 MergedContainers 列表中

推荐列表的实际样例

一个典型的扩容推荐如下所示:

{  
  "TargetMemory": "512MB",  
  "TargetContainer": "container-abc123",  
  "MergedContainers": ["container-def456", "container-ghi789"]  
}

底层资源管理机制

  1. ResourceManager接口

系统通过ResourceManager接口统一管理资源操作: resource.go:36-55

  1. 资源配置计算

GetResourceConfigByReadableMemory函数根据内存需求计算相应的CPU配置: resource.go:161-177

这里使用了基于内存的CPU比例计算,确保资源配置的合理性。

  1. Cgroup资源更新

底层通过cgroup机制实现资源限制的动态调整: resource.go:285-295 cgroup_manage_linux.go:319-347

扩容执行流程

  1. 容器冻结和缩容

在Funclet中,扩容操作首先冻结被合并的容器并将其资源缩减到最小: warmup.go:315-322 warmup.go:330-340

  1. 目标容器扩容

然后为目标容器分配扩展后的资源配置: warmup.go:323-327

资源同步和监控

系统通过定期任务同步资源状态: task.go:68-103

这确保了Controller和Funclet之间的资源状态一致性。