监控您的应用#
本节通过以下方式帮助您调试和监控 Serve 应用:
查看 Ray dashboard
查看
serve status
输出使用 Ray 日志记录和 Loki
检查内置的 Ray Serve 指标
将指标导出到 Arize 平台
Ray Dashboard#
您可以使用 Ray dashboard 获取 Ray 集群和 Ray Serve 应用状态的高级概述。这包括以下详细信息:
当前运行的部署副本数量
Serve 控制器、部署副本和代理的日志
在 Ray 集群中运行的 Ray 节点(即机器)。
您可以在集群 URI 的 8265 端口访问 Ray dashboard。例如,如果您在本地运行 Ray Serve,可以在浏览器中访问 http://localhost:8265
来访问 dashboard。
通过访问Serve 页面查看有关您应用的重要信息。

本示例有一个单节点集群,运行一个名为 Translator
的部署。此部署有 2 个副本。
通过浏览 Serve 页面查看这些副本的详细信息。在每个副本的详细信息页面。在那里,您可以查看有关副本的元数据以及副本的日志,包括由副本进程生成的 logging
和 print
语句。
另一个有用的视图是Actor 视图。这个示例 Serve 应用使用四个Ray Actor
1 个 Serve 控制器
1 个 HTTP 代理
2 个
Translator
部署副本
您可以在 Serve 页面和 Actor 页面中查看这些实体的详细信息。此页面包括其他有用的信息,例如每个 Actor 的进程 ID (PID) 和每个 Actor 日志的链接。您还可以查看特定 Actor 是存活还是死亡,以帮助您调试潜在的集群故障。
提示
要了解有关 Serve 控制器 Actor、HTTP 代理 Actor、部署副本以及它们如何协同工作的更多信息,请查看Serve 架构文档。
有关 Ray dashboard 的详细概述,请参阅dashboard 文档。
使用 Serve CLI 检查应用#
两个 Serve CLI 命令可帮助您检查生产中的 Serve 应用:serve config
和 serve status
。如果您有远程集群,serve config
和 serve status
也有一个 --address/-a
参数用于访问集群。有关此参数的更多信息,请参阅VM 部署。
serve config
获取 Ray 集群收到的最新配置文件。此配置文件表示 Serve 应用的目标状态。Ray 集群通过部署、恢复失败的副本以及执行其他相关操作,不断努力达到并保持此状态。
使用生产指南中的 serve_config.yaml
示例
$ ray start --head
$ serve deploy serve_config.yaml
...
$ serve config
name: default
route_prefix: /
import_path: text_ml:app
runtime_env:
pip:
- torch
- transformers
deployments:
- name: Translator
num_replicas: 1
user_config:
language: french
- name: Summarizer
num_replicas: 1
serve status
获取您的 Serve 应用的当前状态。此命令报告在 Ray 集群上运行的 proxies
和 applications
的状态。
proxies
列出每个代理的状态。每个代理都通过其运行节点的节点 ID 进行标识。代理有三种可能的状态:
STARTING
:代理正在启动,尚未准备好服务请求。HEALTHY
:代理能够服务请求。它运行正常。UNHEALTHY
:代理健康检查失败。它将被终止,并在该节点上启动一个新的代理。DRAINING
:代理健康但已关闭新的请求。它可能包含仍在处理中的待处理请求。DRAINED
:代理已关闭新的请求。没有待处理的请求。
applications
包含应用列表、它们的总体状态以及它们的部署状态。 applications
中的每个条目将应用名称映射到四个字段:
status
:Serve 应用有四种可能的总体状态:"NOT_STARTED"
:此集群上未部署任何应用。"DEPLOYING"
:应用当前正在执行serve deploy
请求。它正在部署新部署或更新现有部署。"RUNNING"
:应用处于稳定状态。它已完成执行所有先前的serve deploy
请求,并正在尝试维护由最新serve deploy
请求设置的目标状态。"DEPLOY_FAILED"
:最新的serve deploy
请求失败。
message
:提供当前状态的上下文信息。deployment_timestamp
:Serve 收到最后一个serve deploy
请求时的 UNIX 时间戳。ServeController
使用本地时钟计算此时间戳。deployments
:表示每个部署状态的条目列表。每个条目将部署名称映射到三个字段:status
:Serve 部署有六种可能的状态:"UPDATING"
:部署正在更新以达到先前deploy
请求设置的目标状态。"HEALTHY"
:部署健康并以目标副本数运行。"UNHEALTHY"
:部署更新后变得不健康。此情况可能是由于副本扩容失败、副本健康检查失败或一般的系统或机器错误。"DEPLOY_FAILED"
:部署启动或更新失败。此情况可能是由于部署构造函数中的错误。"UPSCALING"
:部署(启用自动扩缩容)正在增加副本数量。"DOWNSCALING"
:部署(启用自动扩缩容)正在减少副本数量。
replica_states
:副本状态和该状态下的副本数量列表。每个副本有五种可能的状态:STARTING
:副本正在启动,尚未准备好服务请求。UPDATING
:副本正在进行reconfigure
更新。RECOVERING
:副本正在恢复其状态。RUNNING
:副本正常运行并能够服务请求。STOPPING
:副本正在停止。
message
:提供当前状态的上下文信息。
部署后及整个生命周期内,使用 serve status
命令检查您的部署。
使用前面章节中的 serve_config.yaml
示例
$ ray start --head
$ serve deploy serve_config.yaml
...
$ serve status
proxies:
cef533a072b0f03bf92a6b98cb4eb9153b7b7c7b7f15954feb2f38ec: HEALTHY
applications:
default:
status: RUNNING
message: ''
last_deployed_time_s: 1694041157.2211847
deployments:
Translator:
status: HEALTHY
replica_states:
RUNNING: 1
message: ''
Summarizer:
status: HEALTHY
replica_states:
RUNNING: 1
message: ''
对于使用 KubeRay 的 Kubernetes 部署,serve status
与 Kubernetes 有更紧密的集成。请参阅在 Kubernetes 中获取 Serve 应用状态。
在 Python 中获取应用详情#
调用 serve.status()
API 可在 Python 中获取 Serve 应用详情。serve.status()
在 dataclass
中返回的信息与 serve status
CLI 命令相同。在部署或 Ray 驱动脚本中使用此方法获取 Ray 集群上 Serve 应用的实时信息。例如,此 monitoring_app
报告集群上所有 RUNNING
的 Serve 应用:
from typing import List, Dict
from ray import serve
from ray.serve.schema import ServeStatus, ApplicationStatusOverview
@serve.deployment
def get_healthy_apps() -> List[str]:
serve_status: ServeStatus = serve.status()
app_statuses: Dict[str, ApplicationStatusOverview] = serve_status.applications
running_apps = []
for app_name, app_status in app_statuses.items():
if app_status.status == "RUNNING":
running_apps.append(app_name)
return running_apps
monitoring_app = get_healthy_apps.bind()
Ray 日志记录#
为了理解系统级行为并在运行时显示应用级详细信息,您可以利用 Ray 日志记录。
Ray Serve 使用 Python 标准的 logging
模块,日志记录器名称为 "ray.serve"
。默认情况下,日志从 Actor 同时输出到 stderr
和每个节点的磁盘上的 /tmp/ray/session_latest/logs/serve/
路径。这包括 Serve 控制器和代理的系统级日志,以及从部署副本中产生的访问日志和自定义用户日志。
在开发中,日志会流式传输到 Ray 驱动程序(调用 serve.run()
的 Python 脚本或 serve run
CLI 命令),因此在调试时保持驱动程序运行很方便。
例如,让我们运行一个基本的 Serve 应用并查看其发出的日志。
首先,创建一个简单的部署,当它被查询时记录自定义日志消息
# File name: monitoring.py
from ray import serve
import logging
from starlette.requests import Request
logger = logging.getLogger("ray.serve")
@serve.deployment
class SayHello:
async def __call__(self, request: Request) -> str:
logger.info("Hello world!")
return "hi"
say_hello = SayHello.bind()
使用 serve run
CLI 命令运行此部署
$ serve run monitoring:say_hello
2023-04-10 15:57:32,100 INFO scripts.py:380 -- Deploying from import path: "monitoring:say_hello".
[2023-04-10 15:57:33] INFO ray._private.worker::Started a local Ray instance. View the dashboard at http://127.0.0.1:8265
(ServeController pid=63503) INFO 2023-04-10 15:57:35,822 controller 63503 deployment_state.py:1168 - Deploying new version of deployment SayHello.
(ProxyActor pid=63513) INFO: Started server process [63513]
(ServeController pid=63503) INFO 2023-04-10 15:57:35,882 controller 63503 deployment_state.py:1386 - Adding 1 replica to deployment SayHello.
2023-04-10 15:57:36,840 SUCC scripts.py:398 -- Deployed Serve app successfully.
serve run
会立即打印一些日志消息。请注意,其中一些消息以以下标识符开头,例如
(ServeController pid=63881)
这些消息是来自 Ray Serve Actor 的日志。它们描述了哪个 Actor(Serve 控制器、代理或部署副本)创建了日志以及其进程 ID(这在区分不同的部署副本或代理时很有用)。其余日志消息是 Actor 生成的实际日志语句。
当 serve run
运行时,我们可以在单独的终端窗口中查询该部署
curl -X GET http://localhost:8000/
这将导致 HTTP 代理和部署副本将日志语句打印到运行 serve run
的终端
(ServeReplica:SayHello pid=63520) INFO 2023-04-10 15:59:45,403 SayHello SayHello#kTBlTj HzIYOzaEgN / monitoring.py:16 - Hello world!
(ServeReplica:SayHello pid=63520) INFO 2023-04-10 15:59:45,403 SayHello SayHello#kTBlTj HzIYOzaEgN / replica.py:527 - __CALL__ OK 0.5ms
注意
日志消息包括日志级别、时间戳、部署名称、副本标签、请求 ID、路由、文件名和行号。
您可以在 /tmp/ray/session_latest/logs/serve/
找到这些日志的副本。您可以使用 ELK 或 Loki 等日志记录栈解析这些存储的日志,以便按部署或副本进行搜索。
Serve 支持通过设置环境变量 RAY_ROTATION_MAX_BYTES
和 RAY_ROTATION_BACKUP_COUNT
对这些日志进行日志轮换。
要抑制副本级日志或以其他方式配置日志记录,请在部署构造函数内部配置 "ray.serve"
日志记录器
import logging
logger = logging.getLogger("ray.serve")
@serve.deployment
class Silenced:
def __init__(self):
logger.setLevel(logging.ERROR)
这控制了哪些日志写入到 STDOUT 或磁盘上的文件。除了标准的 Python 日志记录器,Serve 还支持自定义日志记录。自定义日志记录允许您控制哪些消息写入到 STDOUT/STDERR、磁盘上的文件或两者。
有关 Ray 日志记录的详细概述,请参阅Ray 日志记录。
配置 Serve 日志记录#
从 Ray 2.9 版本开始,logging_config
API 配置 Ray Serve 的日志记录。您可以配置 Ray Serve 的日志记录。将 LoggingConfig 的字典或对象传递给 serve.run
或 @serve.deployment
的 logging_config
参数。
配置日志格式#
您可以通过将 encoding=JSON
传递给 serve.run
或 @serve.deployment
中的 logging_config
参数来配置 JSON 日志格式
import requests
from ray import serve
from ray.serve.schema import LoggingConfig
@serve.deployment
class Model:
def __call__(self) -> int:
return "hello world"
serve.run(Model.bind(), logging_config=LoggingConfig(encoding="JSON"))
resp = requests.get("http://localhost:8000/")
import requests
from ray import serve
from ray.serve.schema import LoggingConfig
@serve.deployment(logging_config=LoggingConfig(encoding="JSON"))
class Model:
def __call__(self) -> int:
return "hello world"
serve.run(Model.bind())
resp = requests.get("http://localhost:8000/")
在副本 Model
的日志文件中,您应该看到以下内容
# cat `ls /tmp/ray/session_latest/logs/serve/replica_default_Model_*`
{"levelname": "INFO", "asctime": "2024-02-27 10:36:08,908", "deployment": "default_Model", "replica": "rdofcrh4", "message": "replica.py:855 - Started initializing replica."}
{"levelname": "INFO", "asctime": "2024-02-27 10:36:08,908", "deployment": "default_Model", "replica": "rdofcrh4", "message": "replica.py:877 - Finished initializing replica."}
{"levelname": "INFO", "asctime": "2024-02-27 10:36:10,127", "deployment": "default_Model", "replica": "rdofcrh4", "request_id": "f4f4b3c0-1cca-4424-9002-c887d7858525", "route": "/", "application": "default", "message": "replica.py:1068 - Started executing request to method '__call__'."}
{"levelname": "INFO", "asctime": "2024-02-27 10:36:10,127", "deployment": "default_Model", "replica": "rdofcrh4", "request_id": "f4f4b3c0-1cca-4424-9002-c887d7858525", "route": "/", "application": "default", "message": "replica.py:373 - __CALL__ OK 0.6ms"}
注意
环境变量 RAY_SERVE_ENABLE_JSON_LOGGING=1
将在下一版本中弃用。要全局启用 JSON 日志记录,请使用 RAY_SERVE_LOG_ENCODING=JSON
。
禁用访问日志#
注意
访问日志是 Ray Serve 的流量日志,每个请求都会打印到代理日志文件和副本日志文件。有时它对调试很有用,但有时也会很嘈杂。
您还可以通过将 disable_access_log=True
传递给 @serve.deployment
的 logging_config
参数来禁用访问日志。例如
import requests
import logging
from ray import serve
@serve.deployment(logging_config={"enable_access_log": False})
class Model:
def __call__(self):
logger = logging.getLogger("ray.serve")
logger.info("hello world")
serve.run(Model.bind())
resp = requests.get("http://localhost:8000/")
Model 副本日志文件不包含 Serve 流量日志,您应该只在日志文件中看到应用日志。
# cat `ls /tmp/ray/session_latest/logs/serve/replica_default_Model_*`
INFO 2024-02-27 15:43:12,983 default_Model 4guj63jr replica.py:855 - Started initializing replica.
INFO 2024-02-27 15:43:12,984 default_Model 4guj63jr replica.py:877 - Finished initializing replica.
INFO 2024-02-27 15:43:13,492 default_Model 4guj63jr 2246c4bb-73dc-4524-bf37-c7746a6b3bba / <stdin>:5 - hello world
在不同的部署和应用中配置日志记录#
您还可以通过将 logging_config
传递给 serve.run
来在应用级别配置日志记录。例如
import requests
import logging
from ray import serve
@serve.deployment
class Router:
def __init__(self, handle):
self.handle = handle
async def __call__(self):
logger = logging.getLogger("ray.serve")
logger.debug("This debug message is from the router.")
return await self.handle.remote()
@serve.deployment(logging_config={"log_level": "INFO"})
class Model:
def __call__(self) -> int:
logger = logging.getLogger("ray.serve")
logger.debug("This debug message is from the model.")
return "hello world"
serve.run(Router.bind(Model.bind()), logging_config={"log_level": "DEBUG"})
resp = requests.get("http://localhost:8000/")
在 Router 日志文件中,您应该看到以下内容
# cat `ls /tmp/ray/session_latest/logs/serve/replica_default_Router_*`
INFO 2024-02-27 16:05:10,738 default_Router cwnihe65 replica.py:855 - Started initializing replica.
INFO 2024-02-27 16:05:10,739 default_Router cwnihe65 replica.py:877 - Finished initializing replica.
INFO 2024-02-27 16:05:11,233 default_Router cwnihe65 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / replica.py:1068 - Started executing request to method '__call__'.
DEBUG 2024-02-27 16:05:11,234 default_Router cwnihe65 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / <stdin>:7 - This debug message is from the router.
INFO 2024-02-27 16:05:11,238 default_Router cwnihe65 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / router.py:308 - Using router <class 'ray.serve._private.replica_scheduler.pow_2_scheduler.PowerOfTwoChoicesReplicaScheduler'>.
DEBUG 2024-02-27 16:05:11,240 default_Router cwnihe65 long_poll.py:157 - LongPollClient <ray.serve._private.long_poll.LongPollClient object at 0x10daa5a80> received updates for keys: [(LongPollNamespace.DEPLOYMENT_CONFIG, DeploymentID(name='Model', app='default')), (LongPollNamespace.RUNNING_REPLICAS, DeploymentID(name='Model', app='default'))].
INFO 2024-02-27 16:05:11,241 default_Router cwnihe65 pow_2_scheduler.py:255 - Got updated replicas for deployment 'Model' in application 'default': {'default#Model#256v3hq4'}.
DEBUG 2024-02-27 16:05:11,241 default_Router cwnihe65 long_poll.py:157 - LongPollClient <ray.serve._private.long_poll.LongPollClient object at 0x10daa5900> received updates for keys: [(LongPollNamespace.DEPLOYMENT_CONFIG, DeploymentID(name='Model', app='default')), (LongPollNamespace.RUNNING_REPLICAS, DeploymentID(name='Model', app='default'))].
INFO 2024-02-27 16:05:11,245 default_Router cwnihe65 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / replica.py:373 - __CALL__ OK 12.2ms
在 Model 日志文件中,您应该看到以下内容
# cat `ls /tmp/ray/session_latest/logs/serve/replica_default_Model_*`
INFO 2024-02-27 16:05:10,735 default_Model 256v3hq4 replica.py:855 - Started initializing replica.
INFO 2024-02-27 16:05:10,735 default_Model 256v3hq4 replica.py:877 - Finished initializing replica.
INFO 2024-02-27 16:05:11,244 default_Model 256v3hq4 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / replica.py:1068 - Started executing request to method '__call__'.
INFO 2024-02-27 16:05:11,244 default_Model 256v3hq4 4db9445d-fc9e-490b-8bad-0a5e6bf30899 / replica.py:373 - __CALL__ OK 0.6ms
当您在应用级别设置 logging_config
时,Ray Serve 会应用于应用中的所有部署。同时在部署级别设置 logging_config
时,部署级别的配置将覆盖应用级别的配置。
配置 Serve 组件的日志记录#
您还可以通过将 logging_config
传递给 serve.start
,像上面一样更新 Serve 控制器和代理的日志配置。
from ray import serve
serve.start(
logging_config={
"encoding": "JSON",
"log_level": "DEBUG",
"enable_access_log": False,
}
)
设置请求 ID#
您可以通过在请求头中包含 X-Request-ID
并从响应中检索请求 ID,为每个 HTTP 请求设置自定义请求 ID。例如
from ray import serve
import requests
@serve.deployment
class Model:
def __call__(self) -> int:
return 1
serve.run(Model.bind())
resp = requests.get("http://localhost:8000", headers={"X-Request-ID": "123-234"})
print(resp.headers["X-Request-ID"])
自定义请求 ID 123-234
可以在打印到 HTTP 代理日志文件和部署日志文件中的访问日志中看到。
HTTP 代理日志文件
INFO 2023-07-20 13:47:54,221 http_proxy 127.0.0.1 123-234 / default http_proxy.py:538 - GET 200 8.9ms
部署日志文件
(ServeReplica:default_Model pid=84006) INFO 2023-07-20 13:47:54,218 default_Model default_Model#yptKoo 123-234 / default replica.py:691 - __CALL__ OK 0.2ms
注意
请求 ID 用于关联系统中的日志。避免发送重复的请求 ID,这可能在调试时导致混淆。
使用 Loki 过滤日志#
您可以使用 Loki 浏览和过滤日志。在 Kubernetes 上设置和配置很简单,但作为教程,我们手动设置 Loki。
对于此演练,您需要 Loki 和 Promtail,它们都由 Grafana Labs 支持。按照 Grafana 网站上的安装说明获取 Loki 和 Promtail 的可执行文件。为了方便起见,将 Loki 和 Promtail 可执行文件保存在同一目录中,然后在终端中导航到此目录。
现在,让我们使用 Promtail 将您的日志导入 Loki。
将以下文件保存为 promtail-local-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
scrape_configs:
- job_name: ray
static_configs:
- labels:
job: ray
__path__: /tmp/ray/session_latest/logs/serve/*.*
与 Ray Serve 相关的部分是 static_configs
字段,我们在其中使用 __path__
指示了日志文件的位置。表达式 *.*
将匹配所有文件,但不会匹配目录,因为这会在 Promtail 中导致错误。
我们将在本地运行 Loki。在终端中使用以下命令获取 Loki 的默认配置文件
wget https://raw.githubusercontent.com/grafana/loki/v2.1.0/cmd/loki/loki-local-config.yaml
现在启动 Loki
./loki-darwin-amd64 -config.file=loki-local-config.yaml
在这里,您可能需要将 ./loki-darwin-amd64
替换为您的 Loki 可执行文件的路径,该文件名可能因您的操作系统而异。
启动 Promtail 并传入我们之前保存的配置文件的路径
./promtail-darwin-amd64 -config.file=promtail-local-config.yaml
同样,您可能需要将 ./promtail-darwin-amd64
替换为您的 Promtail 可执行文件。
运行以下 Python 脚本,部署一个带有 Serve 部署日志记录器的基本 Serve 部署并发送一些请求
from ray import serve
import logging
import requests
logger = logging.getLogger("ray.serve")
@serve.deployment
class Counter:
def __init__(self):
self.count = 0
def __call__(self, request):
self.count += 1
logger.info(f"count: {self.count}")
return {"count": self.count}
counter = Counter.bind()
serve.run(counter)
for i in range(10):
requests.get("http://127.0.0.1:8000/")
现在安装并运行 Grafana,然后导航到 http://localhost:3000
,您可以在其中使用默认凭据登录
用户名:admin
密码:admin
在欢迎页面上,单击“Add your first data source”,然后单击“Loki”以将 Loki 添加为数据源。
现在单击左侧面板中的“Explore”。您已准备好运行一些查询!
要过滤所有这些 Ray 日志,只保留与我们的部署相关的日志,请使用以下 LogQL 查询
{job="ray"} |= "Counter"
您应该看到类似以下内容

您可以使用 Loki 过滤 Ray Serve 日志并更快地收集洞察信息。
内置 Ray Serve 指标#
您可以利用内置的 Ray Serve 指标更深入地了解应用性能。
Ray Serve 通过Ray 指标监控基础设施暴露重要的系统指标,例如成功和失败请求的数量。默认情况下,指标以 Prometheus 格式在每个节点上暴露。
注意
通过 Python DeploymentHandle
调用部署时和通过 HTTP 调用部署时,收集的指标不同。
请参阅下面列出的、为每种情况标记的指标。
Ray Serve 暴露以下指标
名称 |
字段 |
描述 |
---|---|---|
|
|
此副本中已处理的查询数。 |
|
|
部署中发生的异常数。 |
|
|
此副本因故障而重启的次数。 |
|
|
此部署副本是否健康。1 表示健康,0 表示不健康。 |
|
|
处理查询的延迟。 |
|
|
当前正在处理的查询数。 |
|
|
处理的 HTTP 请求数。 |
|
|
处理的 gRPC 请求数。 |
|
|
非 200 HTTP 响应数。 |
|
|
非 OK gRPC 响应数。 |
|
|
HTTP 代理中正在进行的请求数。 |
|
|
gRPC 代理中正在进行的请求数。 |
|
|
路由器处理的请求数。 |
|
|
路由器中的请求调度任务数。 |
|
|
路由器中正在经历回退的请求调度任务数。 |
|
|
此 DeploymentHandle 处理的请求数。 |
|
|
已提交给此部署副本的当前请求数。 |
|
|
已分配并发送到副本上执行的当前请求数。 |
|
|
每个部署返回的非 200 HTTP 响应数。 |
|
|
每个部署返回的非 OK gRPC 响应数。 |
|
|
HTTP 请求的端到端延迟(从 Serve HTTP 代理测量)。 |
|
|
gRPC 请求的端到端延迟(从 Serve gRPC 代理测量)。 |
|
|
加载模型所需的时间。 |
|
|
卸载模型所需的时间。 |
|
|
当前副本上加载的模型数量。 |
|
|
当前副本上卸载模型的次数。 |
|
|
当前副本上加载模型的次数。 |
|
|
当前副本上注册的多路复用模型 ID。 |
|
|
获取多路复用模型的调用次数。 |
[*] - 仅在使用代理调用时可用
[**] - 仅在使用 Python DeploymentHandle
调用时可用
[†] - 高级用法开发者指标;未来版本中可能会更改
要实际查看此功能,首先运行以下命令启动 Ray 并设置指标导出端口
ray start --head --metrics-export-port=8080
然后运行以下脚本
from ray import serve
import time
import requests
@serve.deployment
def sleeper():
time.sleep(1)
s = sleeper.bind()
serve.run(s)
while True:
requests.get("http://localhost:8000/")
请求循环运行,直到按 Control-C
取消。
当此脚本运行时,在您的 Web 浏览器中访问 localhost:8080
。在输出中,您可以搜索 serve_
以找到上面的指标。指标默认每十秒更新一次,因此您需要刷新页面以查看新值。可以使用以下配置选项修改指标报告间隔率(请注意,这不是稳定的公共 API,可能会在不通知的情况下更改)
ray start --head --system-config='{"metrics_report_interval_ms": 1000}'
例如,运行脚本一段时间后并刷新 localhost:8080
,您应该找到类似以下的指标
ray_serve_deployment_processing_latency_ms_count{..., replica="sleeper#jtzqhX"} 48.0
ray_serve_deployment_processing_latency_ms_sum{..., replica="sleeper#jtzqhX"} 48160.6719493866
这表明平均处理延迟刚好超过一秒,符合预期。
您甚至可以为部署定义一个自定义指标,并使用部署或副本元数据对其进行标记。这是一个示例:
from ray import serve
from ray.serve import metrics
import time
import requests
@serve.deployment
class MyDeployment:
def __init__(self):
self.num_requests = 0
self.my_counter = metrics.Counter(
"my_counter",
description=("The number of odd-numbered requests to this deployment."),
tag_keys=("model",),
)
self.my_counter.set_default_tags({"model": "123"})
def __call__(self):
self.num_requests += 1
if self.num_requests % 2 == 1:
self.my_counter.inc()
my_deployment = MyDeployment.bind()
serve.run(my_deployment)
while True:
requests.get("http://localhost:8000/")
time.sleep(1)
发出的日志包括
# HELP ray_my_counter_total The number of odd-numbered requests to this deployment.
# TYPE ray_my_counter_total counter
ray_my_counter_total{..., deployment="MyDeployment",model="123",replica="MyDeployment#rUVqKh"} 5.0
有关更多详细信息,包括使用 Prometheus 抓取这些指标的说明,请参阅Ray 指标文档。
性能分析内存#
Ray 提供了两个有用的指标来跟踪内存使用情况:ray_component_rss_mb
(常驻集大小)和 ray_component_mem_shared_bytes
(共享内存)。通过从常驻集大小中减去共享内存(即 ray_component_rss_mb
- ray_component_mem_shared_bytes
)来估算 Serve Actor 的内存使用情况。
如果您注意到 Serve Actor 存在内存泄漏,可以使用 memray
进行调试(pip install memray
)。设置环境变量 RAY_SERVE_ENABLE_MEMORY_PROFILING=1
,然后运行您的 Serve 应用。所有 Serve Actor 都将运行一个 memray
跟踪器,将其内存使用情况记录到 /tmp/ray/session_latest/logs/serve/
目录中的 bin
文件。运行 memray flamegraph [bin file]
命令生成内存使用情况的火焰图。有关更多信息,请参阅 memray 文档。
将指标导出到 Arize#
除了使用 Prometheus 查看 Ray 指标外,Ray Serve 还具有将指标导出到其他可观测性平台的灵活性。
Arize 是一个机器学习可观测性平台,可以帮助您监控实时模型性能,使用可解释性与切片分析查明模型故障/性能下降的根本原因,并发现漂移、数据质量、数据一致性问题等。
要与 Arize 集成,请将 Arize 客户端代码直接添加到您的 Serve 部署代码中。(示例代码)