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导致进程异常。
验证方法
- 启动容器后,用
docker stats实时监控内存变化,看是否还会持续无限制增长。 - 进入容器,执行
ray status查看Ray集群状态,重点看Object Store Memory Usage是否稳定或能自动回收。 - 用
ps aux | grep ray查看Ray进程数量,确认不会持续堆积。
内容的提问来源于stack exchange,提问作者SangYoon Lee
相关产品推荐
相关产品推荐

