MLflow 跟踪服务器
MLflow 跟踪服务器是一个独立的 HTTP 服务器,提供多个 REST API 端点用于跟踪运行/实验。虽然 MLflow 跟踪可以在本地环境中使用,但在团队开发工作流程中托管跟踪服务器功能强大。
- 协作:多个用户可以将运行日志记录到同一个端点,并查询其他用户记录的运行和模型。
- 共享结果:跟踪服务器还提供跟踪 UI 端点,团队成员可以在其中轻松地探索彼此的结果。
- 集中访问:跟踪服务器可以作为元数据和工件远程访问的代理运行,从而更容易保护和审计数据访问。
启动跟踪服务器
启动跟踪服务器就像运行以下命令一样简单
mlflow server --host 127.0.0.1 --port 8080
一旦服务器开始运行,您应该会看到以下输出
[2023-11-01 10:28:12 +0900] [28550] [INFO] Starting gunicorn 20.1.0
[2023-11-01 10:28:12 +0900] [28550] [INFO] Listening at: http://127.0.0.1:8080 (28550)
[2023-11-01 10:28:12 +0900] [28550] [INFO] Using worker: sync
[2023-11-01 10:28:12 +0900] [28552] [INFO] Booting worker with pid: 28552
[2023-11-01 10:28:12 +0900] [28553] [INFO] Booting worker with pid: 28553
[2023-11-01 10:28:12 +0900] [28555] [INFO] Booting worker with pid: 28555
[2023-11-01 10:28:12 +0900] [28558] [INFO] Booting worker with pid: 28558
...
有许多配置服务器的选项,请参阅配置服务器了解更多详情。
服务器默认监听https://:5000,并且只接受来自本地机器的连接。要让服务器接受来自其他机器的连接,您需要传递--host 0.0.0.0
以监听所有网络接口(或特定的接口地址)。这通常是在Kubernetes pod 或 Docker 容器中运行服务器时所需的配置。
请注意,出于安全原因,不建议在公共网络上运行的服务器执行此操作。您应该考虑使用像 NGINX 或 Apache httpd 这样的反向代理,或通过 VPN 连接(请参阅保护跟踪服务器了解更多详情)。
日志记录到跟踪服务器
一旦跟踪服务器启动,通过将MLFLOW_TRACKING_URI
环境变量设置为服务器的 URI(包含其方案和端口,例如http://10.0.0.1:5000
)来连接您的本地客户端,或者调用mlflow.set_tracking_uri()
。
mlflow.start_run()
、mlflow.log_param()
和mlflow.log_metric()
调用将向您的远程跟踪服务器发出 API 请求。
- Python
- R
- Scala
import mlflow
remote_server_uri = "..." # set to your server URI, e.g. http://127.0.0.1:8080
mlflow.set_tracking_uri(remote_server_uri)
mlflow.set_experiment("/my-experiment")
with mlflow.start_run():
mlflow.log_param("a", 1)
mlflow.log_metric("b", 2)
library(mlflow)
install_mlflow()
remote_server_uri = "..." # set to your server URI
mlflow_set_tracking_uri(remote_server_uri)
mlflow_set_experiment("/my-experiment")
mlflow_log_param("a", "1")
import org.mlflow.tracking.MlflowClient
val remoteServerUri = "..." // set to your server URI
val client = new MlflowClient(remoteServerUri)
val experimentId = client.createExperiment("my-experiment")
client.setExperiment(experimentId)
val run = client.createRun(experimentId)
client.logParam(run.getRunId(), "a", "1")
在 Databricks 上,mlflow.set_experiment()
中实验名称必须是工作区中的有效绝对路径(例如,/Workspace/Users/mlflow-experiments/my-experiment
)。
配置服务器
本节描述了如何为一些常见用例配置跟踪服务器。请运行mlflow server --help
以获取完整的命令行选项列表。
后端存储
默认情况下,跟踪服务器将运行元数据日志记录到./mlruns
目录下的本地文件系统。您可以通过添加--backend-store-uri
选项来配置不同的后端存储。
mlflow server --backend-store-uri sqlite:///my.db
这将在当前目录中创建一个 SQLite 数据库my.db
,客户端的日志请求将指向此数据库。
远程工件存储
使用跟踪服务器进行代理工件访问
默认情况下,跟踪服务器将其工件存储在./mlartifacts
目录下的本地文件系统中。要配置跟踪服务器连接到远程存储并提供工件,请使用--artifacts-destination
标志启动服务器。
mlflow server \
--host 0.0.0.0 \
--port 8885 \
--artifacts-destination s3://my-bucket
通过此设置,MLflow 服务器作为访问远程工件的代理工作。MLflow 客户端向服务器发出 HTTP 请求以获取工件。
如果您正在使用远程存储,则必须配置服务器访问工件的凭据。请注意,MLflow 工件代理访问服务使用户能够以跟踪服务器可访问的假定角色访问所有工件。请参阅管理访问了解更多详情。
跟踪服务器将客户端跟踪请求中的 URI mlflow-artifacts:/
解析为明确的对象存储目标(例如,“s3:/my_bucket/mlartifacts”),以便与工件进行交互。以下模式都将解析为配置的代理对象存储位置(在上述示例中,s3://my-root-bucket/mlartifacts
)
https://<主机>:<端口>/mlartifacts
http://<主机>/mlartifacts
mlflow-artifacts://<主机>/mlartifacts
mlflow-artifacts://<主机>:<端口>/mlartifacts
mlflow-artifacts:/mlartifacts
MLflow 客户端按每次运行缓存工件位置信息。因此,不建议在运行终止之前更改其工件位置。
不代理工件访问的情况下使用跟踪服务器
在某些情况下,您可能希望直接访问远程存储,而无需通过跟踪服务器进行代理。在这种情况下,您可以使用--no-serve-artifacts
标志启动服务器,并将--default-artifact-root
设置为您想要重定向请求的远程存储 URI。
mlflow server --no-serve-artifacts --default-artifact-root s3://my-bucket
通过此设置,MLflow 客户端仍然会向跟踪服务器发出最少的 HTTP 请求以获取正确的远程存储 URI,但可以直接将工件上传到/从远程存储下载。虽然这可能不是访问和安全治理的最佳实践,但当您想避免通过跟踪服务器代理工件的开销时,它可能很有用。
如果 MLflow 服务器未配置--serve-artifacts
选项,客户端会直接将工件推送到工件存储。它默认不通过跟踪服务器代理这些工件。
因此,客户端需要直接访问工件存储。有关设置这些凭据的说明,请参阅工件存储文档。
创建实验时,跟踪服务器配置中的工件存储位置会记录在实验的元数据中。启用代理工件存储时,在非代理模式下运行跟踪服务器时创建的任何现有实验将继续使用非代理工件位置。为了使用代理工件日志记录,必须创建一个新实验。如果以-serve-artifacts
模式启用跟踪服务器的目的是消除客户端对底层存储进行身份验证的需要,则应为客户端创建新实验,以便在此迁移后跟踪服务器可以处理身份验证。
可选地专门使用跟踪服务器实例处理工件
MLflow 跟踪服务器可以配置为使用不同的后端存储和工件存储,并为客户端提供单一端点。
然而,如果跟踪服务器请求量足够大并出现性能问题,可以将跟踪服务器配置为在--artifacts-only
模式下提供服务,与指定了--no-serve-artifacts
的实例协同运行。此配置可确保工件的处理与所有其他跟踪服务器事件处理隔离。
当跟踪服务器配置为--artifacts-only
模式时,除工件处理相关的任务(即模型日志记录、加载模型、日志记录工件、列出工件等)外,任何任务都将返回 HTTPError。请参阅以下 Python 客户端 REST 调用示例,该调用尝试从配置为--artifacts-only
模式的服务器列出实验
# Launch the artifact-only server
mlflow server --artifacts-only ...
import requests
# Attempt to list experiments from the server
response = requests.get("http://0.0.0.0:8885/api/2.0/mlflow/experiments/list")
>> HTTPError: Endpoint: /api/2.0/mlflow/experiments/list disabled due to the mlflow server running in `--artifacts-only` mode.
使用额外的 MLflow 服务器专门处理工件对于大规模 MLOps 基础设施很有用。将耗时更长、计算密集型的工件处理任务与更快速、更高容量的其他跟踪 API 请求的元数据功能分离,有助于最大程度地减少单个 MLflow 服务器处理两种类型负载的负担。
如果 MLflow 服务器使用--artifacts-only
标志运行,客户端应通过为工件的 URI 位置引用包含host
或host:port
定义来显式地与此服务器交互。否则,所有工件请求都将路由到 MLflow 跟踪服务器,从而违背了运行独立工件服务器的目的。
保护跟踪服务器
--host
选项将服务公开到所有接口。如果在生产环境中运行服务器,我们建议不要广泛公开内置服务器(因为它未经身份验证且未加密),而是将其置于像 NGINX 或 Apache httpd 这样的反向代理之后,或通过 VPN 连接。
然后,您可以使用这些环境变量将身份验证头传递给 MLflow。
MLFLOW_TRACKING_USERNAME
和MLFLOW_TRACKING_PASSWORD
- 用于 HTTP 基本身份验证的用户名和密码。要使用基本身份验证,您必须设置两个
环境变量。MLFLOW_TRACKING_TOKEN
- 用于 HTTP Bearer 身份验证的令牌。如果设置了基本身份验证,则基本身份验证优先。MLFLOW_TRACKING_INSECURE_TLS
- 如果设置为字面值true
,MLflow 不会验证 TLS 连接,这意味着它不验证https://
跟踪 URI 的证书或主机名。不建议在生产环境中使用此标志。如果此设置为true
,则不得设置MLFLOW_TRACKING_SERVER_CERT_PATH
。MLFLOW_TRACKING_SERVER_CERT_PATH
- 要使用的 CA 包路径。设置requests.request
函数的verify
参数(请参阅requests 主接口)。当您使用自签名服务器证书时,可以使用此项在客户端进行验证。如果设置了此项,则不得设置MLFLOW_TRACKING_INSECURE_TLS
(为 false)。MLFLOW_TRACKING_CLIENT_CERT_PATH
- SSL 客户端证书文件 (.pem) 的路径。设置requests.request
函数的cert
参数(请参阅requests 主接口)。这可用于使用(自签名)客户端证书。
跟踪服务器版本控制
通过查询/version
端点可以找到服务器上运行的 MLflow 版本。这可用于在运行实验之前检查客户端 MLflow 版本是否与远程跟踪服务器同步。例如
import requests
import mlflow
response = requests.get("http://<mlflow-host>:<mlflow-port>/version")
assert response.text == mlflow.__version__ # Checking for a strict version match
模型版本源验证
跟踪服务器可以配置为使用正则表达式模式验证模型版本源。此安全功能有助于确保只有来自经批准来源的模型版本才能注册到您的模型注册表。
配置
启动跟踪服务器时设置MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX
环境变量
export MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX="^mlflow-artifacts:/.*$"
mlflow server --host 0.0.0.0 --port 5000
用法
设置此环境变量后,跟踪服务器将根据指定的正则表达式模式验证模型版本创建请求中的source
参数。如果源不匹配该模式,请求将被拒绝并返回错误。
示例:仅限于 MLflow 工件
仅允许来自 MLflow 工件存储的模型版本
export MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX="^mlflow-artifacts:/.*$"
mlflow server --host 0.0.0.0 --port 5000
通过此配置
import mlflow
from mlflow import MlflowClient
client = MlflowClient("https://:5000")
# This will work - source matches the pattern
client.create_model_version(
name="my-model",
source="mlflow-artifacts://1/artifacts/model",
run_id="abc123",
)
# This will fail - source doesn't match the pattern
client.create_model_version(
name="my-model",
source="s3://my-bucket/model",
run_id="def456",
) # Raises MlflowException: Invalid model version source
示例:仅限于特定的 S3 存储桶
仅允许来自特定 S3 存储桶的模型版本
export MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX="^s3://(production-models|staging-models)/.*$"
mlflow server --host 0.0.0.0 --port 5000
此模式将允许以下来源,例如
s3://production-models/model-v1/
s3://staging-models/experiment-123/model/
但会拒绝以下来源,例如
s3://untrusted-bucket/model/
file:///local/path/model
- 如果未设置环境变量,则不执行源验证。
- 该验证仅适用于
/mlflow/model-versions/create
API 端点。 - 正则表达式使用 Python 的
re.search()
函数应用。 - 使用标准正则表达式语法进行模式匹配。
处理上传/下载大型工件时的超时
当通过启用了工件代理的跟踪服务器上传或下载大型工件时,服务器可能需要很长时间才能处理请求。如果超过超时限制(默认 30 秒),服务器将重新启动工作进程,导致客户端请求失败。
客户端代码示例
import mlflow
mlflow.set_tracking_uri("<TRACKING_SERVER_URI>")
with mlflow.start_run():
mlflow.log_artifact("large.txt")
客户端回溯
Traceback (most recent call last):
File "/Users/user/python3.10/site-packages/requests/adapters.py", line 486, in send
resp = conn.urlopen(
File "/Users/user/python3.10/site-packages/urllib3/connectionpool.py", line 826, in urlopen
return self.urlopen(
...
File "/Users/user/python3.10/site-packages/urllib3/connectionpool.py", line 798, in urlopen
retries = retries.increment(
File "/Users/user/python3.10/site-packages/urllib3/util/retry.py", line 592, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='mlflow.example.com', port=443): Max retries exceeded with url: ... (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:2426)')))
During handling of the above exception, another exception occurred:
跟踪服务器日志
[2025-01-10 11:59:00 +0000] [82] [INFO] Starting gunicorn 20.1.0
[2025-01-10 11:59:00 +0000] [82] [DEBUG] Arbiter booted
[2025-01-10 11:59:00 +0000] [82] [INFO] Listening at: http://0.0.0.0:5000 (82)
...
[2025-01-10 11:59:01 +0000] [82] [CRITICAL] WORKER TIMEOUT (pid:86)
[2025-01-10 11:59:01 +0000] [86] [INFO] Worker exiting (pid: 86)
[2025-01-10 11:59:01 +0000] [179] [INFO] Booting worker with pid: 179
为了缓解此问题,可以在启动服务器时使用--gunicorn-opts
选项增加超时时间,如下所示
mlflow server --gunicorn-opts "--timeout=60" ...
请参阅 Gunicorn 文档中的超时。