帮你快速理解、总结文档立即下载
文档中心>Agent Runtime>Agent 集群>实践教程>测试 Agent 工作负载启动性能

测试 Agent 工作负载启动性能

最近更新时间:2026-10-09 18:52:00
我的收藏
批量创建代码执行环境、扩容办公助手或启动 RL Rollout 任务前,可以先测试 Agent 集群的工作负载启动速度。本教程在同一个计算节点上依次完成预热、串行启动和并行启动测试,比较单个 Pod 的启动延迟、整批就绪时间和运行稳定性。
测试使用配套工具创建模拟 Agent 应用的 Pod,不需要编译 Cube 或负载发生器。完成后,您将得到两组可对比的结果,以及每轮测试的配置、日志和事件文件。

测试范围与指标

默认工作负载在普通 Linux 容器中执行 sleep infinity,以 Pod 进入 Ready 状态作为启动完成信号。它用于测量轻量工作负载的启动基线,不包含业务初始化、真实 LLM 请求或任务完成时间。
测试
Pod 数量
提交速率
最大在途创建请求数
用途
预热
1
1 QPS
1
准备镜像与运行环境,不计入正式结果。
串行启动
16
1 QPS
1
建立逐个提交工作负载时的基线。
并行启动
16
16 QPS
16
观察批量启动时的整体耗时与尾延迟。
串行测试是逐个发出创建请求,并不等待前一个 Pod 完成业务或退出。并行测试约在 1 秒内提交 16 个 Pod,也不是所有请求在同一瞬间发出。
重点比较以下指标:
单 Pod 启动延迟:从开始创建 Pod,到发生器首次观察到该 Pod Ready,记录 P50、P95、P99 和最大值。
整批就绪时间:从批次开始到全部 Pod 就绪,包含按配置速率提交请求的时间。
成功率与稳定性:创建、调度、容器启动和就绪数量是否齐全,以及就绪后 10 秒观察期内是否重启或丢失就绪状态。
计时在集群内的负载发生器中完成。Scheduled、ContainersStarted 和 Ready 均是通过 Watch/List 观察到的状态时间,因此结果包含控制面、调度和状态传播的影响,不能当作 Cube 内部沙箱创建接口的纯执行耗时。

开始前准备

使用专用测试集群或隔离测试节点。工具会创建测试命名空间、权限和 RuntimeClass,并为发生器节点添加标签及 NoSchedule 污点;同一集群不要同时运行多套该测试。
通过控制台准备集群和节点池,操作请参见 创建集群和节点池。本教程需要两个不同的节点:一个运行被测工作负载,另一个运行负载发生器。
项目
要求
目标节点
状态为 Ready,已启用 Cube 运行时,具有 agc.cloud.tencent.com/cube-ready=true 标签;Kubernetes 可分配 CPU 不低于 16 核。
目标节点剩余容量
能同时容纳 16 个测试 Pod。默认每个 Pod 申请 512m CPU 和 512Mi 内存,还需留出系统开销、临时存储、Pod 槽位、Pod IP 和运行时资源。
发生器节点
状态为 Ready,与目标节点不同;至少剩余 16100m CPU 和约 5 GiB 内存。
操作机
使用能连接集群 API 的 Linux 主机,安装 Bash、Git、kubectl、jq、Mike Farah yq v4 及 GNU coreutils(包含 sha256sum)。
操作权限
使用测试集群管理员身份,允许创建测试资源、权限和 RuntimeClass,以及修改发生器节点标签与污点。
镜像访问
目标节点能拉取工作负载镜像,发生器节点能拉取工具中固定 digest 的发生器镜像。
标签用于检查已经安装好的运行环境,不要手工补上标签来替代运行时安装。连接配置获取方法请参见 通过 Kubernetes API 访问 Agent 集群。

第一步:下载并校验工具

工具位于 ags-cookbook 的 performance-test-tools 目录,包含运行脚本、清理脚本、工作负载清单和校验文件。本文固定使用 cube-cri-performance-test-tools-v1.0.17 对应的仓库提交,便于重复测试时保持工具一致。
在操作机的 Bash 终端中执行。后续步骤继续使用同一终端,以保留参数和每轮测试 ID。
git clone https://github.com/TencentCloudAgentRuntime/ags-cookbook.git agc-performance-cookbook
cd agc-performance-cookbook
git checkout --detach 46619b344e56b25b317ff7367ee72201f5af7f14
export SCALE_LOAD_DIR="$PWD/benchmarks/agent-cluster/performance-test-tools"
export RESULT_ROOT="$PWD/_output/agc-startup-performance"
检查工具和依赖:
kubectl version --client
jq --version
yq --version
cat "$SCALE_LOAD_DIR/VERSION"
chmod +x "$SCALE_LOAD_DIR/run.sh" "$SCALE_LOAD_DIR/cleanup.sh"
bash -n "$SCALE_LOAD_DIR/run.sh" "$SCALE_LOAD_DIR/cleanup.sh" "$SCALE_LOAD_DIR/sop-functions.sh"
(cd "$SCALE_LOAD_DIR" && sha256sum -c SHA256SUMS)
test -r "$SCALE_LOAD_DIR/manifests/cube-cri-load-simple-pod.yaml"
test -r "$SCALE_LOAD_DIR/manifests/cube-cri-load-runtimeclass.yaml"
确认校验项全部为 OK 后继续。校验失败时重新取得相同提交的完整工具目录,不修改校验文件跳过检查。发生器以容器镜像交付,脚本已固定其 digest,无需本地构建。

第二步:设置参数并检查节点

替换 kubeconfig 路径及两个节点名称。工作负载镜像需要包含 sleep 命令,并与节点架构兼容;两组测试使用相同镜像。进行多轮或跨日期比较时,建议固定镜像 digest。
export KUBECONFIG='/absolute/path/to/kubeconfig'
export TARGET_NODE='REPLACE_WITH_TARGET_NODE'
export GENERATOR_NODE='REPLACE_WITH_GENERATOR_NODE'
export LOAD_IMAGE='mirror.ccs.tencentyun.com/library/ubuntu:24.04'
export TEST_PODS=16
export SNAPSHOTTER_PROFILE=overlayfs

kubectl config current-context
kubectl cluster-info
kubectl get nodes -o wide
kubectl get node "$TARGET_NODE" "$GENERATOR_NODE" -L agc.cloud.tencent.com/cube-ready
kubectl describe node "$TARGET_NODE"
kubectl describe node "$GENERATOR_NODE"
在节点详情中检查 Allocatable、Allocated resources 和现有 Pod,确认剩余资源满足上表要求。节点标称规格不等于可分配资源,可分配资源也不等于尚未使用的资源。
执行以下检查;任意一项不通过时,先处理节点选择或权限问题,不继续运行测试:
if [[ "$TARGET_NODE" == "$GENERATOR_NODE" ]]; then
echo '目标节点和发生器节点不能相同。' >&2
elif [[ "$(kubectl auth can-i '*' '*')" != yes ]]; then
echo '当前身份没有测试集群管理员权限。' >&2
else
echo '节点选择和管理员权限检查通过,请继续核对节点资源及运行环境。'
fi
初始化测试命令:
source "$SCALE_LOAD_DIR/sop-functions.sh"

第三步:预热

使用与正式测试相同的工作负载模板和镜像,运行一个 Pod。就绪后观察 10 秒,成功后自动清理该轮资源,结果单独保存在本地。
run_warmup_test
看到 Warm-up succeeded. 后再进行正式测试。预热失败时停止,按输出中的目录保存和检查诊断材料。更换目标节点、镜像或工作负载类型后,需要重新预热。
本教程比较预热后的启动表现,不将结果写成首次拉取镜像时的冷启动性能。正式轮次的镜像状态标记不能代替预热步骤。

第四步:串行启动测试

默认工作负载使用 cube-load RuntimeClass,在目标节点上执行 sleep infinity,每个 Pod 的 CPU、内存 requests 与 limits 均为 512m、512Mi。工具自动生成命名空间和唯一 Pod 名称,无需手工修改或提交清单。
按 1 QPS、1 worker 提交 16 个 Pod:
run_serial_test "$TEST_PODS"
成功时会输出摘要并自动清理本轮集群资源,本地结果保留。检查 count、created、scheduled、containersStarted、ready 是否均为 16,随后记录延迟分位值、整批就绪时间、重启与 Warning 情况。
需要再次查看本轮结果时执行:
show_result "$SERIAL_RUN_ID"
确认本轮成功并完成清理后,再进入并行测试。失败时先排查,不跳过失败轮次继续扩大压力。

第五步:并行启动测试

保持目标节点、工作负载镜像和类型不变,确认节点容量已经释放,再执行:
run_parallel_test "$TEST_PODS"
该命令令 count=qps=workers=16,在约 1 秒内提交 16 个 Pod。workers 表示最大在途创建请求数,实际值取决于请求完成速度。成功时同样会输出结果并清理该轮资源。
重新查看结果:
show_result "$PARALLEL_RUN_ID"

第六步:比较结果

show_result 会先校验结果文件的完整性,再输出便于阅读的摘要。按下面的对应关系记录串行与并行两组结果:
检查项
摘要中的字段
如何解读
创建和就绪数量
count、created、scheduled、containersStarted、ready
对照计划数量,不能只统计成功样本而忽略失败任务。
单 Pod 启动耗时
latencyMs.createToReady
记录 P50、P95、P99 和最大值,单位毫秒。
整批环境就绪
batchMs.allReady
包含按速率提交请求的时间,适合衡量整批资源何时可用。
实际请求速率
actualRequestWriteQPS
核对压力是否接近配置速率。
稳定性
restartCount、readyLost
结合 10 秒稳定观察期判断是否存在重启或就绪丢失。
告警与错误
warnings、errors
查看原因和受影响 Pod;最终成功也可能伴随过程中发生的 Warning。
工具判定
success、accepted、slo
同时查看是否配置延迟阈值,不能只凭 accepted=true 推导达到某个速度。
默认教程命令不启用正值延迟 SLO。需要按业务目标判定时,在正式测试前设置 READY_P99_SLO_MS 为所需毫秒阈值,并在结果中核对 slo。该阈值是本次测试目标,不是产品 SLA。

原 SOP 的输出示例

以下仅用于说明如何比较结果,来自原 SOP 的示例输出,不是本次教程新增的实测结果,也不是固定达标值。
检查项
串行:16 Pod,1 QPS
并行:16 Pod,16 QPS
就绪数量
16 / 16
16 / 16
Create → Ready P50
约 325 毫秒
约 410 毫秒
Create → Ready P95 / P99
约 357 / 357 毫秒
约 1295 / 1295 毫秒
Create → Ready 最大值
约 357 毫秒
约 1295 毫秒
整批全部就绪
约 15.34 秒
约 2.23 秒
重启 / 就绪丢失次数
0 / 0
0 / 0
Warning
0
1,原因为 FailedCreatePodSandBox
串行组的整批时间包含约 15 秒的分批提交间隔;并行组更早提交完全部 Pod,因此整批就绪更快,但单 Pod 的尾延迟可能增加。这是同一运行时在两种提交方式下的比较,不能据此推导不同运行时的性能差异。16 个样本的 P99 也不能用于估算大规模长期尾延迟。

保存测试记录

每轮结果位于 $RESULT_ROOT/<run-id>/,重点保存:
文件
用途
batch-summary.json
完整结果摘要;与 show_result 展示结构不同,后者做了字段整理。
run-config.json
本轮节点、镜像、并发、工作负载类型等参数。
pods.jsonl
单 Pod 观测记录。
generator.log
发生器日志。
warning-events.json
工作负载 Warning 事件。
artifacts.sha256
结果文件校验信息。
同时记录集群及运行时版本、节点规格与架构、测试期间的已有负载和工具版本。需要增加样本量时,在每轮完成清理后重复测试;不要把不同镜像、工作负载类型或缓存条件的样本混在一起。

失败排查与资源清理

现象
优先检查
发生器 Pod 无法调度
发生器节点剩余 CPU、内存、污点及镜像拉取条件。
工作负载 Pending
目标节点资源、Pod IP、Pod 数量上限、节点选择条件和工作区配置。
FailedCreatePodSandBox
目标节点的 Cube 运行环境、运行时资源和相关事件。
镜像拉取失败
镜像地址、架构、仓库权限和节点网络。
延迟明显增大
镜像是否预热、节点其他负载、实际提交速率及调度和就绪阶段的耗时。
结果校验失败或文件不完整
保留已有目录,检查发生器退出状态及文件回传,不作为有效性能样本。
提示已有测试资源
先查清资源归属,结束并清理前一轮,不覆盖其他测试。
成功轮次会自动清理;失败、中断或资源残留时,使用对应的精确 run-id 清理。例如清理当前终端中失败的并行轮次:
cleanup_test "$PARALLEL_RUN_ID"
预热和串行轮次分别使用 $WARMUP_RUN_ID、$SERIAL_RUN_ID。终端重开后,从保存的配置或终端记录中取得实际 run-id,重新加载参数与函数后再清理,不猜测或复用 ID。
所有轮次结束且不再有测试 Pod 后,清理共享资源和发生器节点标记:
cleanup_shared_test_resources
工具会检查资源归属和残留 Pod;检查不通过时停止清理,不应通过修改标签绕过。清理后核对发生器节点上的测试标签和污点已经移除。本地 $RESULT_ROOT 不会被删除,集群和节点池也不会被该命令释放;测试环境不再使用时,另按 删除集群 处理。

进阶测试

使用更接近业务的工作负载

默认 simple 类型只有轻量常驻进程。需要观察初始化和健康检查的影响时,使用包含 Node.js 的镜像,并在三步中一致指定 production:
export LOAD_IMAGE='mirror.ccs.tencentyun.com/library/node:22-bookworm-slim'
run_warmup_test --workload-profile production
run_serial_test "$TEST_PODS" --workload-profile production
run_parallel_test "$TEST_PODS" --workload-profile production
以上命令应逐条执行,每一步成功并清理后再继续。该类型包含 init container、主服务、Sidecar、volume、HTTP/TCP 健康检查和 NET_ADMIN,执行前需确认测试环境允许这些权限和资源配置。完整清单位于工具目录的 manifests/cube-cri-load-pod.yaml。
此时 Ready 更接近“服务可以接收请求”,但仍不包含真实模型调用或完整 Agent 任务。其结果应与 simple 分开记录;真正的业务启动指标还需由业务镜像和就绪检查定义。

测试 EROX 镜像加速

基础测试默认使用 overlayfs。测试 EROX 前,先完成镜像加速开通并取得已转换的测试镜像及 digest,请参见 使用镜像加速。将参数替换为实际镜像后重新预热,再依次执行测试:
export SNAPSHOTTER_PROFILE=erox
export LOAD_IMAGE='REPLACE_WITH_EROX_IMAGE@sha256:REPLACE_WITH_DIGEST'
run_warmup_test
run_serial_test "$TEST_PODS"
run_parallel_test "$TEST_PODS"
每一步成功后再继续。切换参数本身不会安装 EROX 或转换镜像。EROX 与 overlayfs 的结果分开记录;镜像身份差异用于诊断,不单独作为该工具的验收条件。

扩大规模

先核算节点剩余资源,再逐级增加 TEST_PODS。默认每个 simple Pod 申请 512m CPU、512Mi 内存和一个 Pod IP,还需检查节点 Pod 数上限及 Cube/NBD 等运行时资源。工具中的 cube-load RuntimeClass 未额外声明资源 overhead,这不代表运行时本身没有资源开销。
每档规模至少重复两轮,保持并行组 count=qps=workers=TEST_PODS。上一档出现失败时先排查;需要更多样本时优先清理后重复测试,不超出单节点剩余承载量。

参考资料