添加端到端容错#
本节将帮助您
为您的 Serve 应用程序提供额外的容错能力
了解 Serve 的恢复程序
模拟 Serve 应用程序中的系统错误
指南:为您的 Serve 应用添加端到端容错#
Serve 开箱即用提供了一些 容错 功能。以下是实现端到端容错的两种选择:
调整这些功能并在 KubeRay 之上运行 Serve
使用 Anyscale 平台,一个托管的 Ray 平台
副本健康检查#
默认情况下,Serve 控制器会定期对每个 Serve 部署副本进行健康检查,并在失败时重新启动它。
您可以定义自定义的应用程序级别健康检查,并调整其频率和超时。要定义自定义健康检查,请将 check_health 方法添加到您的部署类。此方法不应接受任何参数,也不应返回任何结果,如果 Ray Serve 认为副本不健康,则应引发异常。如果健康检查失败,Serve 控制器会记录异常,终止不健康的副本,然后重新启动它们。您还可以使用部署选项来自定义 Serve 运行健康检查的频率以及 Serve 将副本标记为不健康的超时时间。
@serve.deployment(health_check_period_s=10, health_check_timeout_s=30)
class MyDeployment:
def __init__(self, db_addr: str):
self._my_db_connection = connect_to_db(db_addr)
def __call__(self, request):
return self._do_something_cool()
# Called by Serve to check the replica's health.
def check_health(self):
if not self._my_db_connection.is_connected():
# The specific type of exception is not important.
raise RuntimeError("uh-oh, DB connection is broken.")
在此示例中,如果与外部数据库的连接丢失,check_health 将引发错误。Serve 控制器会定期在部署的每个副本上调用此方法。如果该方法为某个副本引发异常,Serve 会将该副本标记为不健康并重新启动它。健康检查是针对每个副本进行配置和执行的。
注意
您不应通过部署句柄直接调用 check_health(例如,await deployment_handle.check_health.remote())。这将调用单个、任意副本的健康检查。check_health 方法设计为 Serve 控制器的接口,而不是供用户直接调用的。
注意
在可组合的部署图中,每个部署都独立负责自身的健康,而不管它绑定的其他部署。例如,在由 app = ParentDeployment.bind(ChildDeployment.bind()) 定义的应用程序中,如果 ChildDeployment 副本的健康检查失败,ParentDeployment 不会重新启动。当 ChildDeployment 副本恢复时,ParentDeployment 中的句柄会自动更新以将请求路由到健康的副本。
工作节点恢复#
KubeRay 要求
您**必须**使用 KubeRay 部署您的 Serve 应用程序才能使用此功能。
请参阅 Serve 的 Kubernetes 生产指南,了解如何使用 KubeRay 部署您的应用程序。
默认情况下,Serve 可以从某些故障中恢复,例如不健康的 actor。当 Serve 在 Kubernetes 上运行 并使用 KubeRay 时,它还可以从一些集群级故障中恢复,例如损坏的工作节点或头节点。
当工作节点发生故障时,运行在该节点上的 actor 也会失败。Serve 会检测到 actor 失败,并尝试在剩余的健康节点上重新启动这些 actor。同时,KubeRay 会检测到节点本身发生故障,因此它会尝试在另一个正在运行的节点上重新启动工作节点 pod,并会启动一个新的健康节点来替换它。一旦节点启动,如果 pod 仍在挂起状态,它就可以在该节点上重新启动。同样,Serve 也可以在该节点上重新启动任何挂起的 actor。在恢复期间,运行在健康节点上的部署副本可以继续提供流量。
头节点恢复:Ray GCS 容错#
KubeRay 要求
您**必须**使用 KubeRay 部署您的 Serve 应用程序才能使用此功能。
请参阅 Serve 的 Kubernetes 生产指南,了解如何使用 KubeRay 部署您的应用程序。
在本节中,您将学习如何为 Ray 的全局控制存储 (GCS) 添加容错能力,从而使您的 Serve 应用程序即使在头节点崩溃时也能提供流量。
默认情况下,Ray 头节点是单点故障:如果它崩溃,整个 Ray 集群都会崩溃,您必须重新启动它。在 Kubernetes 上运行时,RayService 控制器会检查 Ray 集群的健康状况并在发生这种情况时重新启动它,但这会引入一些停机时间。
从 Ray 2.0+ 开始,KubeRay 支持 全局控制存储 (GCS) 容错,防止 Ray 集群在头节点下线时崩溃。在头节点恢复期间,Serve 应用程序仍然可以由工作节点处理流量,但您无法更新或从 Actor 或工作节点崩溃等其他故障中恢复。一旦 GCS 恢复,集群将恢复正常运行。
您可以通过添加外部 Redis 服务器并修改您的 RayService Kubernetes 对象来启用 KubeRay 上的 GCS 容错,步骤如下:
步骤 1:添加外部 Redis 服务器#
GCS 容错需要外部 Redis 数据库。您可以选择托管自己的 Redis 数据库,也可以通过第三方供应商使用。请使用高可用性的 Redis 数据库以实现弹性。
**用于开发目的**,您也可以在与 Ray 集群相同的 Kubernetes 集群上托管一个小型 Redis 数据库。例如,您可以通过在 Kubernetes YAML 前面添加这三个 Redis 对象来添加一个 1 节点 Redis 集群:
kind: ConfigMap
apiVersion: v1
metadata:
name: redis-config
labels:
app: redis
data:
redis.conf: |-
port 6379
bind 0.0.0.0
protected-mode no
requirepass 5241590000000000
---
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: redis
spec:
type: ClusterIP
ports:
- name: redis
port: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5.0.8
command:
- "sh"
- "-c"
- "redis-server /usr/local/etc/redis/redis.conf"
ports:
- containerPort: 6379
volumeMounts:
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: config
configMap:
name: redis-config
---
**此配置不适用于生产环境**,但对于开发和测试很有用。当您迁移到生产环境时,强烈建议您用高可用的 Redis 集群替换这个 1 节点 Redis 集群。
步骤 2:将 Redis 信息添加到 RayService#
添加 Redis 对象后,您还需要修改 RayService 配置。
首先,您需要更新 RayService 元数据的注解:
...
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
name: rayservice-sample
spec:
...
...
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
name: rayservice-sample
annotations:
ray.io/ft-enabled: "true"
ray.io/external-storage-namespace: "my-raycluster-storage-namespace"
spec:
...
这些注解是:
ray.io/ft-enabled必需:如果为 true,则启用 GCS 容错。ray.io/external-storage-namespace可选:设置 外部存储命名空间。
接下来,您需要将 RAY_REDIS_ADDRESS 环境变量添加到 headGroupSpec:
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
...
spec:
...
rayClusterConfig:
headGroupSpec:
...
template:
...
spec:
...
env:
...
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
...
spec:
...
rayClusterConfig:
headGroupSpec:
...
template:
...
spec:
...
env:
...
- name: RAY_REDIS_ADDRESS
value: redis:6379
RAY_REDIS_ADDRESS 的值应该是您的 Redis 数据库的 redis:// 地址。它应包含您的 Redis 数据库的主机和端口。一个 示例 Redis 地址 是 redis://user:secret@localhost:6379/0?foo=bar&qux=baz。
在上面的示例中,Redis 部署名称(redis)是 Kubernetes 集群内的宿主,Redis 端口是 6379。此示例与上一节的 示例配置 兼容。
在应用了 Redis 对象以及更新后的 RayService 后,您的 Ray 集群就可以从头节点崩溃中恢复,而无需重新启动所有工作节点!
另请参阅
请查看 KubeRay 关于 GCS 容错 的指南,以了解 Serve 如何利用外部 Redis 集群来提供头节点容错。
将副本分散到不同节点#
提高 Serve 应用程序可用性的一种方法是将部署副本分散到多个节点上,这样即使在一定数量的节点发生故障后,您仍然有足够的运行副本可用于提供流量。
默认情况下,Serve 会软分散所有部署副本,但它有一些限制:
分散是软性的,尽力而为,不能保证完全均匀。
Serve 尝试在现有节点之间分散副本(如果可能),而不是启动新节点。例如,如果您有一个足够大的单节点集群,Serve 会将所有副本调度到该单个节点上,假设它有足够的资源。然而,该节点成为单点故障。
您可以通过 max_replicas_per_node 部署选项 来更改部署的分散行为,它会硬性限制单个节点上给定部署的副本数量。如果您将其设置为 1,则相当于严格分散部署副本。如果未设置,则没有硬性分散限制,Serve 会使用前一段中提到的默认软分散。max_replicas_per_node 选项是每个部署的,并且只影响部署内副本的分散。不同部署的副本之间没有分散。
以下代码示例展示了如何设置 max_replicas_per_node 部署选项:
import ray
from ray import serve
@serve.deployment(max_replicas_per_node=1)
class Deployment1:
def __call__(self, request):
return "hello"
@serve.deployment(max_replicas_per_node=2)
class Deployment2:
def __call__(self, request):
return "world"
此示例有两个 Serve 部署,具有不同的 max_replicas_per_node:Deployment1 每个节点最多可以有一个副本,Deployment2 每个节点最多可以有两个副本。如果您调度 Deployment1 的两个副本和 Deployment2 的两个副本,Serve 会运行一个至少有两个节点的集群,每个节点运行 Deployment1 的一个副本。Deployment2 的两个副本可能会运行在单个节点上,或者分布在两个节点上,因为这两种情况都满足 max_replicas_per_node 约束。
Serve 的恢复程序#
本节解释 Serve 如何从系统故障中恢复。它使用以下 Serve 应用程序和配置作为工作示例。
# File name: sleepy_pid.py
from ray import serve
@serve.deployment
class SleepyPid:
def __init__(self):
import time
time.sleep(10)
def __call__(self) -> int:
import os
return os.getpid()
app = SleepyPid.bind()
# File name: config.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: redis-config
labels:
app: redis
data:
redis.conf: |-
port 6379
bind 0.0.0.0
protected-mode no
requirepass 5241590000000000
---
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: redis
spec:
type: ClusterIP
ports:
- name: redis
port: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5.0.8
command:
- "sh"
- "-c"
- "redis-server /usr/local/etc/redis/redis.conf"
ports:
- containerPort: 6379
volumeMounts:
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: config
configMap:
name: redis-config
---
apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
name: rayservice-sample
annotations:
ray.io/ft-enabled: "true"
spec:
serviceUnhealthySecondThreshold: 300
deploymentUnhealthySecondThreshold: 300
serveConfig:
importPath: "sleepy_pid:app"
runtimeEnv: |
working_dir: "https://github.com/ray-project/serve_config_examples/archive/42d10bab77741b40d11304ad66d39a4ec2345247.zip"
deployments:
- name: SleepyPid
numReplicas: 6
rayActorOptions:
numCpus: 0
rayClusterConfig:
rayVersion: '2.3.0'
headGroupSpec:
replicas: 1
rayStartParams:
num-cpus: '2'
dashboard-host: '0.0.0.0'
redis-password: "5241590000000000"
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.3.0
imagePullPolicy: Always
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: RAY_REDIS_ADDRESS
value: redis:6379
resources:
limits:
cpu: 2
memory: 2Gi
requests:
cpu: 2
memory: 2Gi
ports:
- containerPort: 6379
name: redis
- containerPort: 8265
name: dashboard
- containerPort: 10001
name: client
- containerPort: 8000
name: serve
workerGroupSpecs:
- replicas: 2
minReplicas: 2
maxReplicas: 2
groupName: small-group
rayStartParams:
node-ip-address: $MY_POD_IP
template:
spec:
containers:
- name: machine-learning
image: rayproject/ray:2.3.0
imagePullPolicy: Always
env:
- name: RAY_DISABLE_DOCKER_CPU_WARNING
value: "1"
- name: TYPE
value: "worker"
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: machine-learning
resource: requests.cpu
- name: CPU_LIMITS
valueFrom:
resourceFieldRef:
containerName: machine-learning
resource: limits.cpu
- name: MEMORY_LIMITS
valueFrom:
resourceFieldRef:
containerName: machine-learning
resource: limits.memory
- name: MEMORY_REQUESTS
valueFrom:
resourceFieldRef:
containerName: machine-learning
resource: requests.memory
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
ports:
- containerPort: 80
name: client
lifecycle:
preStop:
exec:
command: ["/bin/sh","-c","ray stop"]
resources:
limits:
cpu: "1"
memory: "2Gi"
requests:
cpu: "500m"
memory: "2Gi"
遵循 KubeRay 快速入门指南 来:
安装
kubectl和Helm准备一个 Kubernetes 集群
部署 KubeRay 操作员
然后,部署上述 Serve 应用程序。
$ kubectl apply -f config.yaml
工作节点故障#
您可以在工作示例中模拟工作节点故障。首先,查看 Kubernetes 集群中正在运行的节点和 pod:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-serve-demo-default-pool-ed597cce-nvm2 Ready <none> 3d22h v1.22.12-gke.1200
gke-serve-demo-default-pool-ed597cce-m888 Ready <none> 3d22h v1.22.12-gke.1200
gke-serve-demo-default-pool-ed597cce-pu2q Ready <none> 3d22h v1.22.12-gke.1200
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ervice-sample-raycluster-thwmr-worker-small-group-bdv6q 1/1 Running 0 3m3s 10.68.2.62 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
ervice-sample-raycluster-thwmr-worker-small-group-pztzk 1/1 Running 0 3m3s 10.68.2.61 gke-serve-demo-default-pool-ed597cce-m888 <none> <none>
rayservice-sample-raycluster-thwmr-head-28mdh 1/1 Running 1 (2m55s ago) 3m3s 10.68.0.45 gke-serve-demo-default-pool-ed597cce-pu2q <none> <none>
redis-75c8b8b65d-4qgfz 1/1 Running 0 3m3s 10.68.2.60 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
打开一个单独的终端窗口并端口转发到其中一个工作节点:
$ kubectl port-forward ervice-sample-raycluster-thwmr-worker-small-group-bdv6q 8000
Forwarding from 127.0.0.1:8000 -> 8000
Forwarding from [::1]:8000 -> 8000
当 port-forward 运行时,您可以在另一个终端窗口中查询应用程序:
$ curl localhost:8000
418
输出是处理请求的部署副本的进程 ID。该应用程序启动了 6 个部署副本,因此如果您多次运行查询,应该会看到不同的进程 ID。
$ curl localhost:8000
418
$ curl localhost:8000
256
$ curl localhost:8000
385
现在您可以模拟工作节点故障。您有两个选择:杀死一个工作节点 pod 或杀死一个工作节点。让我们先从工作节点 pod 开始。请确保杀死您**没有**进行端口转发的 pod,这样当另一个 pod 重新启动时,您就可以继续查询正在运行的 pod。
$ kubectl delete pod ervice-sample-raycluster-thwmr-worker-small-group-pztzk
pod "ervice-sample-raycluster-thwmr-worker-small-group-pztzk" deleted
$ curl localhost:8000
6318
当 pod 崩溃并恢复时,正在运行的 pod 可以继续提供流量!
提示
杀死一个节点并等待其恢复通常比杀死一个 pod 并等待其恢复需要更长的时间。对于这种类型的调试,通过杀死 pod 而不是杀死节点来模拟故障更快捷。
您可以类似地杀死一个工作节点,并看到其他节点可以继续提供流量。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ervice-sample-raycluster-thwmr-worker-small-group-bdv6q 1/1 Running 0 65m 10.68.2.62 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
ervice-sample-raycluster-thwmr-worker-small-group-mznwq 1/1 Running 0 5m46s 10.68.1.3 gke-serve-demo-default-pool-ed597cce-m888 <none> <none>
rayservice-sample-raycluster-thwmr-head-28mdh 1/1 Running 1 (65m ago) 65m 10.68.0.45 gke-serve-demo-default-pool-ed597cce-pu2q <none> <none>
redis-75c8b8b65d-4qgfz 1/1 Running 0 65m 10.68.2.60 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
$ kubectl delete node gke-serve-demo-default-pool-ed597cce-m888
node "gke-serve-demo-default-pool-ed597cce-m888" deleted
$ curl localhost:8000
385
头节点故障#
您可以通过杀死头节点 pod 或头节点来模拟头节点故障。首先,查看集群中正在运行的 pod:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ervice-sample-raycluster-thwmr-worker-small-group-6f2pk 1/1 Running 0 6m59s 10.68.2.64 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
ervice-sample-raycluster-thwmr-worker-small-group-bdv6q 1/1 Running 0 79m 10.68.2.62 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
rayservice-sample-raycluster-thwmr-head-28mdh 1/1 Running 1 (79m ago) 79m 10.68.0.45 gke-serve-demo-default-pool-ed597cce-pu2q <none> <none>
redis-75c8b8b65d-4qgfz 1/1 Running 0 79m 10.68.2.60 gke-serve-demo-default-pool-ed597cce-nvm2 <none> <none>
端口转发到其中一个工作节点 pod。确保此 pod 与头节点在不同的节点上,这样您就可以杀死头节点而不至于崩溃工作节点。
$ kubectl port-forward ervice-sample-raycluster-thwmr-worker-small-group-bdv6q
Forwarding from 127.0.0.1:8000 -> 8000
Forwarding from [::1]:8000 -> 8000
在单独的终端中,您可以向 Serve 应用程序发出请求:
$ curl localhost:8000
418
您可以杀死头节点 pod 来模拟杀死 Ray 头节点:
$ kubectl delete pod rayservice-sample-raycluster-thwmr-head-28mdh
pod "rayservice-sample-raycluster-thwmr-head-28mdh" deleted
$ curl localhost:8000
如果您已在集群中配置了 GCS 容错,则您的工作节点 pod 在头节点 pod 崩溃并恢复时可以继续提供流量,而无需重新启动。如果没有 GCS 容错,KubeRay 会在头节点 pod 崩溃时重新启动所有工作节点 pod,因此您需要等待工作节点重新启动并重新初始化部署,然后才能进行端口转发并发送更多请求。
Serve 控制器故障#
您可以通过手动杀死 Serve actor 来模拟 Serve 控制器故障。
如果您正在运行 KubeRay,请 exec 进入其中一个 pod:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
ervice-sample-raycluster-mx5x6-worker-small-group-hfhnw 1/1 Running 0 118m
ervice-sample-raycluster-mx5x6-worker-small-group-nwcpb 1/1 Running 0 118m
rayservice-sample-raycluster-mx5x6-head-bqjhw 1/1 Running 0 118m
redis-75c8b8b65d-4qgfz 1/1 Running 0 3h36m
$ kubectl exec -it rayservice-sample-raycluster-mx5x6-head-bqjhw -- bash
ray@rayservice-sample-raycluster-mx5x6-head-bqjhw:~$
您可以使用 Ray State API 来检查您的 Serve 应用:
$ ray summary actors
======== Actors Summary: 2022-10-04 21:06:33.678706 ========
Stats:
------------------------------------
total_actors: 10
Table (group by class):
------------------------------------
CLASS_NAME STATE_COUNTS
0 ProxyActor ALIVE: 3
1 ServeReplica:SleepyPid ALIVE: 6
2 ServeController ALIVE: 1
$ ray list actors --filter "class_name=ServeController"
======== List: 2022-10-04 21:09:14.915881 ========
Stats:
------------------------------
Total: 1
Table:
------------------------------
ACTOR_ID CLASS_NAME STATE NAME PID
0 70a718c973c2ce9471d318f701000000 ServeController ALIVE SERVE_CONTROLLER_ACTOR 48570
然后,您可以通过 Python 解释器杀死 Serve 控制器。请注意,您需要使用 ray list actor 输出中的 NAME 来获取 Serve 控制器的句柄。
$ python
>>> import ray
>>> controller_handle = ray.get_actor("SERVE_CONTROLLER_ACTOR", namespace="serve")
>>> ray.kill(controller_handle, no_restart=True)
>>> exit()
您可以使用 Ray State API 检查控制器的状态:
$ ray list actors --filter "class_name=ServeController"
======== List: 2022-10-04 21:36:37.157754 ========
Stats:
------------------------------
Total: 2
Table:
------------------------------
ACTOR_ID CLASS_NAME STATE NAME PID
0 3281133ee86534e3b707190b01000000 ServeController ALIVE SERVE_CONTROLLER_ACTOR 49914
1 70a718c973c2ce9471d318f701000000 ServeController DEAD SERVE_CONTROLLER_ACTOR 48570
在控制器恢复期间,您仍然应该能够查询您的部署。
# If you're running KubeRay, you
# can do this from inside the pod:
$ python
>>> import requests
>>> requests.get("https://:8000").json()
347
注意
在控制器死亡期间,副本健康检查和部署自动伸缩将不起作用。一旦控制器恢复,它们将继续工作。
部署副本故障#
您可以通过手动杀死部署副本来自我模拟副本故障。如果您正在运行 KubeRay,请确保在运行这些命令之前 exec 进入一个 Ray pod。
$ ray summary actors
======== Actors Summary: 2022-10-04 21:40:36.454488 ========
Stats:
------------------------------------
total_actors: 11
Table (group by class):
------------------------------------
CLASS_NAME STATE_COUNTS
0 ProxyActor ALIVE: 3
1 ServeController ALIVE: 1
2 ServeReplica:SleepyPid ALIVE: 6
$ ray list actors --filter "class_name=ServeReplica:SleepyPid"
======== List: 2022-10-04 21:41:32.151864 ========
Stats:
------------------------------
Total: 6
Table:
------------------------------
ACTOR_ID CLASS_NAME STATE NAME PID
0 39e08b172e66a5d22b2b4cf401000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#RlRptP 203
1 55d59bcb791a1f9353cd34e301000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#BnoOtj 348
2 8c34e675edf7b6695461d13501000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#SakmRM 283
3 a95405318047c5528b7483e701000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#rUigUh 347
4 c531188fede3ebfc868b73a001000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#gbpoFe 383
5 de8dfa16839443f940fe725f01000000 ServeReplica:SleepyPid ALIVE SERVE_REPLICA::SleepyPid#PHvdJW 176
您可以使用 ray list actor 输出中的 NAME 来获取其中一个副本的句柄:
$ python
>>> import ray
>>> replica_handle = ray.get_actor("SERVE_REPLICA::SleepyPid#RlRptP", namespace="serve")
>>> ray.kill(replica_handle, no_restart=True)
>>> exit()
在副本重新启动期间,其他副本可以继续处理请求。最终,副本会重新启动并继续提供请求。
$ python
>>> import requests
>>> requests.get("https://:8000").json()
383
代理故障#
您可以通过手动杀死 ProxyActor actors 来模拟代理故障。如果您正在运行 KubeRay,请确保在运行这些命令之前 exec 进入一个 Ray pod。
$ ray summary actors
======== Actors Summary: 2022-10-04 21:51:55.903800 ========
Stats:
------------------------------------
total_actors: 12
Table (group by class):
------------------------------------
CLASS_NAME STATE_COUNTS
0 ProxyActor ALIVE: 3
1 ServeController ALIVE: 1
2 ServeReplica:SleepyPid ALIVE: 6
$ ray list actors --filter "class_name=ProxyActor"
======== List: 2022-10-04 21:52:39.853758 ========
Stats:
------------------------------
Total: 3
Table:
------------------------------
ACTOR_ID CLASS_NAME STATE NAME PID
0 283fc11beebb6149deb608eb01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-91f9a685e662313a0075efcb7fd894249a5bdae7ee88837bea7985a0 101
1 2b010ce28baeff5cb6cb161e01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-cc262f3dba544a49ea617d5611789b5613f8fe8c86018ef23c0131eb 133
2 7abce9dd241b089c1172e9ca01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-7589773fc62e08c2679847aee9416805bbbf260bee25331fa3389c4f 267
您可以使用 ray list actor 输出中的 NAME 来获取其中一个副本的句柄:
$ python
>>> import ray
>>> proxy_handle = ray.get_actor("SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-91f9a685e662313a0075efcb7fd894249a5bdae7ee88837bea7985a0", namespace="serve")
>>> ray.kill(proxy_handle, no_restart=False)
>>> exit()
在代理重新启动期间,其他代理可以继续接受请求。最终,代理会重新启动并继续接受请求。您可以使用 ray list actor 命令查看代理何时重新启动。
$ ray list actors --filter "class_name=ProxyActor"
======== List: 2022-10-04 21:58:41.193966 ========
Stats:
------------------------------
Total: 3
Table:
------------------------------
ACTOR_ID CLASS_NAME STATE NAME PID
0 283fc11beebb6149deb608eb01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-91f9a685e662313a0075efcb7fd894249a5bdae7ee88837bea7985a0 57317
1 2b010ce28baeff5cb6cb161e01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-cc262f3dba544a49ea617d5611789b5613f8fe8c86018ef23c0131eb 133
2 7abce9dd241b089c1172e9ca01000000 ProxyActor ALIVE SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-7589773fc62e08c2679847aee9416805bbbf260bee25331fa3389c4f 267
请注意,第一个 ProxyActor 的 PID 已更改,这表明它已重新启动。