SkyPilot API 服务器性能最佳实践#

此页面介绍了 团队部署 中远程 SkyPilot API 服务器的性能最佳实践。

调整 API 服务器资源#

API 服务器可以同时处理的请求数量与其分配的资源(CPU 核数和内存)成正比。在内部,请求被分为两种不同的类型,并以先入先出(FIFO)的方式处理。

  • 长时间运行请求:执行时间更长、需要更多资源的请求,包括 launchexecjobs.launch 等。

  • 短时间运行请求:执行时间更短或需要更少资源的请求,包括 statuslogs 等。

注意

请求由 API 服务器排队和处理。因此,只有当它们在队列中或正在处理时,才会占用 API 服务器的资源。一旦请求被处理,远程集群开始进行实际工作,它们就不再需要 API 服务器的资源或占用其并发限制。

例如,针对 launchexec 的长时间运行请求,在集群已配置或作业已提交到集群后,分别不再占用 API 服务器的资源。

建议根据预期的并发量调整分配给 API 服务器的资源,以避免排队。

# NAMESPACE and RELEASE_NAME should be the same as the deployment step
helm upgrade -n ${NAMESPACE} ${RELEASE_NAME} skypilot/skypilot-nightly \
    --reuse-values \
    --set apiService.resources.requests.cpu=8 \
    --set apiService.resources.requests.memory=16Gi \
    --set apiService.resources.limits.cpu=8 \
    --set apiService.resources.limits.memory=16Gi

注意

如果您指定的资源低于团队使用的推荐最低资源(4 个 CPU 和 8GB 内存,这也是未指定 apiService.resources 时的默认值),则会在 helm upgrade 时报错。如果性能和稳定性对您的场景不是问题,您可以指定 --set apiService.skipResourcesCheck=true 跳过此检查。

为什么要将限制和请求设置为相同的值?

我们建议将资源限制设置为与请求相同的值,原因如下:

  • API 服务器依赖于资源限制来检测可用资源并决定最大并发量。将限制设置得大于请求或省略限制将导致 API 服务器做出激进的并发决策,并可能导致 Kubernetes 节点上的资源争用较高。

  • 将限制和请求设置为相同的值可确保 API 服务器 pod 的 QoS 等级被设置为 Guaranteed,并降低在节点资源压力下 pod 被 Kubernetes 节点杀死的可能性。

简而言之,将限制和请求设置为相同的值是以资源利用率为代价换取稳定性和可预测性。转向其他权衡也是可能的,但我们建议在生产环境中保持内存请求和限制相同,以避免由节点内存压力引起的潜在逐出。

对于 VM 部署,不支持原地垂直扩缩 API 服务器,需要终止并重新创建 API 服务器才能应用新资源。这意味着 API 服务器的当前状态将会丢失。我们建议创建一个具有新资源的新的 API 服务器实例,并逐步将工作负载迁移到新的 API 服务器。

请参阅 替代方案:部署到云 VM,了解如何在运行 sky launch 之前部署新的 API 服务器并修改集群配置。

resources:
-   cpus: 8+
-   memory: 16+
+   cpus: 16+
+   memory: 32+

下表显示了不同资源配置下的最大并发量。

CPU

内存

最大并发量

建议团队规模

4

8Gi

8 个长时间请求,11 个短时间请求

1~5 个用户

16

32Gi

32 个长时间请求,60 个短时间请求

1~15 个用户

32

64Gi

64 个长时间请求,145 个短时间请求

1~30 个用户

64

128Gi

128 个长时间请求,299 个短时间请求

10~50 个用户

128

256Gi

256 个长时间请求,589 个短时间请求

10~100 个用户

使用异步请求避免阻塞#

排队请求的数量没有限制。为了避免请求阻塞,您可以 (1) 分配更多资源以增加最大并发量(如上所述),或 (2) 异步提交请求 (--async) 并异步轮询状态。

例如:

# Submit 2000 jobs at once without blocking
for i in `seq 1 2000`; do
    sky jobs launch -y --async job.yaml
done
# Poll the status of the jobs
watch -n 5 "sky jobs queue"

请求将在 API 服务器上排队并按提交顺序处理。如果您发现状态一段时间未更新,您可以使用以下命令检查已提交请求的状态:

$ sky api status
ID                                    User  Name             Created         Status
d9c95c7e-d248-4a7f-b72e-636511405357  alice sky.jobs.launch  a few secs ago  PENDING
767182fd-0202-4ae5-b2d7-ddfabea5c821  alice sky.jobs.launch  a few secs ago  PENDING
5667cff2-e953-4b80-9e5f-546cea83dc59  alice sky.jobs.launch  a few secs ago  RUNNING

检查请求日志#

应该有一些 RUNNING 请求占用了并发限制。通常,RUNNING 请求会继续执行,最终您的请求也会被处理,但如果 RUNNING 请求卡住了,您可以使用以下命令检查请求日志:

# Replace <request_id> with the actual request id from the ID column
$ sky api logs <request_id>

取消请求#

如果请求根据日志显示已卡住,例如重试启动库存不足的虚拟机,您可以使用以下命令取消请求:

sky api cancel <requst_id>

避免并发日志请求#

如果您运行 sky logs 来跟踪某个任务的日志,只要被跟踪的任务仍在运行,日志跟踪就会持续占用 API 服务器的资源。因此,并发的日志请求会占用并发限制,并可能延迟其他请求。

为了避免这种情况,如果存在大量并发日志请求,建议使用 --no-follow 标志运行 sky logssky jobs logs

sky logs --no-follow my_cluster

默认情况下,执行任务的命令(例如 sky jobs launchsky exec)在任务启动后也会跟踪任务的日志。您可以添加 --async 标志来提交作业而不跟踪日志。

sky jobs launch --async job.yaml