You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker+FastAPI环境下Ray初始化引发内存泄漏及重复进程生成问题求助

Ray + FastAPI + Docker 内存泄漏与进程堆积问题解决方案

我之前在做Ray+FastAPI+Docker的项目时,也碰到过几乎一模一样的内存泄漏和进程堆积问题,结合你的代码和场景,咱们来一步步排查原因并解决:

1. 先修复代码里的装饰器逻辑(最关键的第一步)

看你的代码,把@app.on_event("startup")、@repeat_every和@app.get("/test")同时装饰在同一个函数上,这会导致多重触发:

  • 容器启动时执行一次test函数
  • 每隔1秒自动重复执行一次test函数
  • 每次访问/test接口时又会执行一次test函数

相当于任务执行频率翻了好几倍,会快速生成大量Ray对象和远程任务,直接加剧内存占用。正确的写法应该把定时任务和API接口分开:

import ray
from fastapi import FastAPI
from fastapi_utils.tasks import repeat_every
import numpy as np

# 只初始化一次Ray,放在最外层
ray.init(
    num_cpus=4,
    dashboard_host='0.0.0.0',
    dashboard_port=8888,
    configure_logging=False
)

app = FastAPI()

# 启动时初始化定时任务
@app.on_event("startup")
def startup():
    # 用repeat_every装饰定时执行的函数,并启动定时
    repeat_every(seconds=1, raise_exceptions=True)(run_periodic_task)()

# 单独的定时任务逻辑
def run_periodic_task():
    dd = []
    bb = ray.put(dd)
    fut = [aa.remote(bb) for _ in range(10)]
    ss = ray.get(fut)
    
    # 主动清理不再需要的Ray对象
    ray.internal.free([bb] + fut)

# 单独的API接口逻辑
@app.get("/test")
def test_api():
    # 如果需要通过接口触发任务,直接调用函数即可
    run_periodic_task()
    return {"status": "task executed"}

@ray.remote
def aa(ss):
    a = np.random.rand(380,640)
    ss.append(a)
    return ss

2. 主动清理Ray对象存储的内存

Ray的对象存储默认不会主动清理已处理完的对象,即使你已经拿到ray.get的结果,这些对象仍会留在内存里。除了上面代码里的ray.internal.free(),还可以通过以下方式优化:

  • 设置对象存储内存上限:在ray.init时添加object_store_memory参数,限制对象存储的最大内存,达到上限时Ray会自动启动GC回收无用对象:
    ray.init(
        # 其他参数
        object_store_memory=512 * 1024 * 1024  # 限制为512MB,根据容器内存调整
    )
    
  • 启用高频内存监控:设置memory_monitor_refresh_ms让Ray更频繁地检查内存并回收:
    ray.init(
        # 其他参数
        memory_monitor_refresh_ms=1000  # 每秒检查一次内存
    )
    

3. 解决Ray进程堆积的问题

Docker容器里出现大量重复的RAY:IDLE、Dashboard进程,主要是这几个原因:

  • 避免重复初始化Ray:确保整个应用只调用一次ray.init(),不要在接口或定时任务里重复调用,否则会启动多个Ray Runtime,导致进程堆积。
  • 关闭不需要的后台服务:如果不需要Ray Dashboard,可以直接关闭它,减少资源占用:
    ray.init(
        num_cpus=4,
        dashboard_port=None,  # 关闭Dashboard
        configure_logging=False
    )
    
  • 用Docker的init进程管理僵尸进程:启动容器时加上--init参数,让Docker自带的tini进程负责回收孤儿进程,避免IDLE进程堆积:
    docker run --init --memory=2g ...  # 同时记得设置内存限制
    

4. 适配Docker容器的资源限制

Ray需要感知容器的资源限制才能合理分配内存,否则可能过度占用:

  • 启动容器时明确设置内存和CPU限制,比如docker run --memory=2g --cpus=4 ...,Ray会自动检测这些限制并调整自身的资源使用策略。
  • ray.init里的num_cpus要和容器的--cpus参数一致,避免Ray过度分配CPU导致进程异常。

验证方法

  1. 启动容器后,用docker stats实时监控内存变化,看是否还会持续无限制增长。
  2. 进入容器,执行ray status查看Ray集群状态,重点看Object Store Memory Usage是否稳定或能自动回收。
  3. 用ps aux | grep ray查看Ray进程数量,确认不会持续堆积。

内容的提问来源于stack exchange,提问作者SangYoon Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:51:17