背景
在边缘计算的场景中,边缘端的资源非常紧张,需要将已经申请的空闲容器做合并。而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
- 资源需求检测
当函数调用到达时,系统首先在OccupyColdRuntime中检测是否需要扩容: runtime_dispatcher.go:187-222
这里的关键逻辑是isNeedScale(memBytes)函数,它通过比较请求内存与基础内存来判断是否需要扩容。
- 资源可用性检查
在分配资源前,系统会通过checkAndMarkResource检查可用资源: runtime_dispatcher.go:378-390
这个函数使用读写锁确保线程安全,先检查可分配内存是否足够,然后标记即将使用的资源。
- 扩容推荐生成
当需要扩容时,系统调用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"]
}
底层资源管理机制
- ResourceManager接口
系统通过ResourceManager接口统一管理资源操作: resource.go:36-55
- 资源配置计算
GetResourceConfigByReadableMemory函数根据内存需求计算相应的CPU配置: resource.go:161-177
这里使用了基于内存的CPU比例计算,确保资源配置的合理性。
- Cgroup资源更新
底层通过cgroup机制实现资源限制的动态调整: resource.go:285-295 cgroup_manage_linux.go:319-347
扩容执行流程
- 容器冻结和缩容
在Funclet中,扩容操作首先冻结被合并的容器并将其资源缩减到最小: warmup.go:315-322 warmup.go:330-340
- 目标容器扩容
然后为目标容器分配扩展后的资源配置: warmup.go:323-327
资源同步和监控
系统通过定期任务同步资源状态: task.go:68-103
这确保了Controller和Funclet之间的资源状态一致性。