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
相关产品推荐
相关产品推荐

