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

Ruby服务Unicorn主进程内存持续增长引发OOM问题求助

解决Unicorn主进程内存泄漏导致fork时OOM的问题

我之前维护Ruby服务时也碰到过几乎一模一样的Unicorn主进程内存持续增长的问题,结合排查和解决经验,给你几个实用的方向:

1. 定位主进程内存泄漏的根源

Unicorn的主进程设计上应该是低内存、稳定运行的,出现内存持续增长大概率是以下原因:

  • 主进程加载了业务代码或动态资源,并且在fork worker后还在持续执行逻辑(比如错误的日志处理、信号回调里的内存泄漏)
  • 开启preload_app true后,主进程里残留了不能被正确释放的对象(比如未关闭的文件句柄、全局变量缓存)

排查方法:

  • 用ps -p <主进程PID> -o rss,vsize定期记录主进程的内存占用,确认增长趋势
  • 使用Ruby的objspace工具,在主进程中定期dump内存对象快照:
    require 'objspace'
    ObjectSpace.dump_all(output: File.open("/tmp/unicorn_master_mem_#{Time.now.to_i}.json", "w"))
    
    对比不同时间的快照,找出持续增长的对象类型,定位泄漏点

2. 兜底:监控主进程内存并自动重启

如果暂时找不到泄漏根源,可以先做兜底措施,避免OOM影响服务:

  • 用monit或者自定义shell脚本监控主进程内存,当超过阈值(比如1GB)时发送SIGQUIT信号让Unicorn优雅重启(新主进程会启动,旧主进程会等所有worker处理完请求后退出)
  • 示例monit配置片段:
    check process unicorn_master with pidfile /var/run/unicorn.pid
      start program = "/etc/init.d/unicorn start"
      stop program = "/etc/init.d/unicorn stop"
      if memory > 1024 MB for 2 cycles then restart
    

3. 优化Unicorn的fork与worker配置

通过调整配置减少主进程fork的频率,降低内存积累的影响:

  • 开启preload_app true:让主进程先加载所有代码和依赖,再fork worker,减少重复加载的内存开销,但要注意在before_fork中关闭数据库连接、清理全局状态,after_fork中重新初始化资源:
    before_fork do |server, worker|
      defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.disconnect!
    end
    
    after_fork do |server, worker|
      defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
    end
    
  • 设置max_requests:让worker处理一定数量的请求后自动退出,主进程会fork新的worker,避免worker内存泄漏间接影响主进程(虽然主进程本身的泄漏是核心问题,但这个配置能降低fork的频率)
    worker_processes 20
    max_requests 10000  # 每个worker处理10000个请求后重启
    

4. 系统层面的临时缓解

  • 调整内核参数vm.overcommit_memory=1:允许系统在内存不足时仍允许fork操作(写时复制机制下,实际不会立即占用全部内存),但这只是应急手段,不能解决根本问题
  • 配置适量的swap空间:避免瞬间内存不足触发OOM killer,但swap会降低性能,仅作为临时缓解

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:19:29