背景#
Ray 是一個統一的框架,能夠實現分散式計算,因為單一伺服器可能無法處理繁重的計算任務。在本文中,我們對 Ray 的兩個重要特性進行深入分析,即多租戶和自動擴展。多租戶允許將不同的資源(如 CPU 和內存)分配給不同的用戶。另一方面,自動擴展根據流量和利用率水平促進實例的增加或移除。
選擇 Kubernetes 的原因#
雖然 Ray 提供了一個官方的自動擴展解決方案,根據資源請求來擴展 Ray 集群,但我們的特定場景需要根據內存使用情況進行自動擴展。因此,我們開發了兩個潛在的解決方案。第一個解決方案涉及利用 Ray 資源監控器來監控每個任務和演員的資源使用情況。考慮到我們已經為每個用戶分配了不同的配額,有必要累積每個任務和演員的資源使用情況。此外,我們必須建立一個機制,以確定何時根據內存使用情況觸發自動擴展。第二個解決方案涉及利用 Kubernetes 水平 Pod 自動擴展器自動調整副本數量,根據內存使用情況。因此,我們在這裡主要選擇第二個解決方案。
建立 Ray 集群#
假設您已經設置了 Kubernetes 和 Harbor 環境,下一步將是安裝 Ray 集群。需要注意的是,您需要修改映像以匹配您的具體配置。
# Ray 頭節點服務,允許工作者 Pod 發現頭節點以進行雙向通信。
# 更多上下文可以在 [端口配置文檔](https://docs.ray.io/en/latest/ray-core/configure.html#ports-configurations) 中找到。
apiVersion: v1
kind: Service
metadata:
name: service-ray-cluster
labels:
app: ray-cluster-head
spec:
clusterIP: None
ports:
- name: client
protocol: TCP
port: 10001
targetPort: 10001
- name: dashboard
protocol: TCP
port: 8265
targetPort: 8265
- name: gcs-server
protocol: TCP
port: 6380
targetPort: 6380
selector:
app: ray-cluster-head
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-ray-head
labels:
app: ray-cluster-head
spec:
# 不要更改這個 - Ray 目前只支持每個集群一個頭節點。
replicas: 1
selector:
matchLabels:
component: ray-head
type: ray
app: ray-cluster-head
template:
metadata:
labels:
component: ray-head
type: ray
app: ray-cluster-head
spec:
# 如果頭節點故障,整個集群(包括所有工作節點)也會故障。如果您希望 Kubernetes 在這種情況下啟動一個新的頭節點,請將其設置為 "Always",否則設置為 "Never"。
restartPolicy: Always
# 此卷為 Ray 分配共享內存以用於其 plasma 對象存儲。如果您不提供此項,Ray 將回退到 /tmp,這會導致速度變慢,如果它不是共享內存卷。
# volumes:
# - name: dshm
# emptyDir:
# medium: Memory
containers:
- name: ray-head
image: rayproject/ray:2.3.0
imagePullPolicy: Always
command: [ "/bin/bash", "-c", "--" ]
# 如果 Redis 沒有密碼,請設置 --redis-password=''
args:
- "ray start --head --port=6380 --num-cpus=$MY_CPU_REQUEST --dashboard-host=0.0.0.0 --object-manager-port=8076 --node-manager-port=8077 --dashboard-agent-grpc-port=8078 --dashboard-agent-listen-port=52365 --redis-password='123456' --block"
ports:
- containerPort: 6380 # GCS 伺服器
- containerPort: 10001 # 用於 Ray 客戶端
- containerPort: 8265 # 用於 Ray 儀表板
# 此卷為 Ray 分配共享內存以用於其 plasma 對象存儲。如果您不提供此項,Ray 將回退到 /tmp,這會導致速度變慢,如果它不是共享內存卷。
# volumeMounts:
# - mountPath: /dev/shm
# name: dshm
env:
# RAY_REDIS_ADDRESS 讓 ray 使用外部 Redis 以實現容錯
- name: RAY_REDIS_ADDRESS
value: redis:6379 # 外部 Redis 的 IP 地址,在此示例中為 "redis:6379"
# 這在 ray start 命令中使用,以便 Ray 可以生成正確數量的進程。省略此項可能會導致性能下降。
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.cpu
resources:
limits:
cpu: "2"
memory: "5G"
requests:
# 對於生產用例,我們建議指定整數 CPU 請求和限制。
# 我們還建議將請求設置為 CPU 和內存的限制相等。
# 在此示例中,我們使用 500m CPU 請求以適應資源受限的本地 Kubernetes 測試環境,例如 KinD 和 minikube。
cpu: "500m"
# Ray 頭節點的剩餘狀態內存使用量約為 1Gb。我們不建議為 Ray 頭 Pod 分配少於 2Gb 的內存。
# 對於生產用例,我們建議為每個 Ray 容器分配至少 8Gb 的內存。
memory: "2G"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-ray-worker
labels:
app: ray-cluster-worker
spec:
# 更改此項以擴展在 Ray 集群中啟動的工作節點數量。
selector:
matchLabels:
component: ray-worker
type: ray
app: ray-cluster-worker
template:
metadata:
labels:
component: ray-worker
type: ray
app: ray-cluster-worker
spec:
restartPolicy: Always
# volumes:
# - name: dshm
# emptyDir:
# medium: Memory
containers:
- name: ray-worker
image: rayproject/ray:2.3.0
imagePullPolicy: Always
command: ["/bin/bash", "-c", "--"]
args:
- "ray start --num-cpus=$MY_CPU_REQUEST --address=service-ray-cluster:6380 --object-manager-port=8076 --node-manager-port=8077 --dashboard-agent-grpc-port=8078 --dashboard-agent-listen-port=52365 --block"
# 此卷為 Ray 分配共享內存以用於其 plasma 對象存儲。如果您不提供此項,Ray 將回退到 /tmp,這會導致速度變慢,如果它不是共享內存卷。
# volumeMounts:
# - mountPath: /dev/shm
# name: dshm
env:
# 這在 ray start 命令中使用,以便 Ray 可以生成正確數量的進程。省略此項可能會導致性能下降。
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.cpu
# 此配置中的資源請求和限制對於生產來說太小了!
# 使用幾個大型 Ray Pod 比使用許多小型 Pod 更好。
# 對於生產,理想情況下是將每個 Ray Pod 的大小設置為佔用其調度的整個 Kubernetes 節點。
resources:
limits:
cpu: "1"
memory: "1G"
# 對於生產用例,我們建議指定整數 CPU 請求和限制。
# 我們還建議將請求設置為 CPU 和內存的限制相等。
# 在此示例中,我們使用 500m CPU 請求以適應資源受限的本地 Kubernetes 測試環境,例如 KinD 和 minikube。
requests:
cpu: "500m"
memory: "1G"
一旦您在伺服器上創建了 ray-dev.yaml
文件,您可以繼續安裝 Ray 頭和工作者。如果您想在 ns
命名空間中安裝 Ray 集群,可以通過執行以下命令來實現:
kubectl apply -f ray-dev.yaml -n ns
在伺服器上創建 ray-dev.yaml
文件並安裝 Ray 頭和工作者後,下一步是為工作者啟用水平 Pod 自動擴展(HPA)。
要為工作者啟用 HPA,您需要在伺服器上創建另一個名為 ray-autoscaler.yaml
的文件。該文件將包含 Kubernetes HPA 對象的配置,該對象將根據 CPU 利用率自動調整工作 Pod 的數量。以下是 ray-autoscaler.yaml
文件的示例:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: ray-autoscaler
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: deployment-ray-worker
minReplicas: 1
maxReplicas: 2
targetCPUUtilizationPercentage: 60
這個 HPA 將根據 CPU 利用率自動調整指定部署的副本數量,最小為 1 個副本,最大為 2 個副本,目標 CPU 利用率為 60%。
要在 ns
命名空間中應用此 HPA,請執行以下命令:
kubectl apply -f ray-autoscaler.yaml -n ns
監控和可觀察性#
下一步是啟用 集群監控。Ray 在頭節點上自動生成一個名為 prom_metrics_service_discovery.json
的 Prometheus 服務發現文件,這有助於指標代理的服務發現。要使用默認的 Kubernetes Prometheus 為您的 Ray 集群啟用監控,您需要將此文件映射出來並將其添加到 Prometheus 配置中。
我們可以更新 ray-dev.yaml
配置文件,以使用持久卷聲明(PVC)來映射 /tmp/ray
目錄(請參閱文檔以獲取更多詳細信息)。這涉及將以下配置添加到 YAML 文件的 volumes
和 volumeMounts
中。最後,我們可以將此 PVC 與我們的 Prometheus 實例關聯。
spec:
volumes:
- name: ray-prom
persistentVolumeClaim:
claimName: ray-prom-pvc
containers:
- name: ray-head
volumeMounts:
- name: ray-prom
mountPath: /tmp/ray