我有一个基于Grape v0.19.2的Ruby v2.3.4应用程序。
最近,在我们上次部署之后,我们注意到系统关闭,我们的神v0.13.7进程监视器再次启动它。在查看了崩溃日志之后,我们每周都会看到20-30次崩溃。
以下是一些示例崩溃报告:
/.rvm/gems/ruby-2.3.4/gems/bson-4.2.1/lib/bson/hash.rb:80: [BUG] rb_gc_mark(): 0x007fa2f4fb33f0 is T_NONE
/.rvm/gems/ruby-2.3.4/gems/mongo-2.4.1/lib/mongo/socket.rb:176: [BUG] rb_gc_mark(): 0x007f990c383360 is T_NONE
/.rvm/gems/ruby-2.3.4/gems/activesupport-5.1.1/lib/active_support/callbacks.rb:102: [BUG] rb_gc_mark(): 0x007ffbeb9e3880 is T_NONE
这些崩溃似乎是随机发生的,可能相隔5-7天,或者一小时内会发生几次。崩溃日志中的堆栈跟踪并不是非常有用,并且基本上显示了我们正在运行的所有内容。
目前我们的策略是回滚整个代码库并查看所有进行的更改,但它们非常多。 30-40更新的宝石的依赖性也发生了变化。由于崩溃似乎是随机的,因此很难测试代码或gem的更改是否已解决问题。
此问题似乎与垃圾收集相关,因此我尝试在调试模式下使用GC来查看是否可以帮助我们创建可重现的案例,但应用程序启动和运行的时间会长几个数量级,因此策略不是&# 39; t可行。
什么是强制崩溃的好策略,以便我们可以缩小问题是来自我们的代码更新还是依赖宝石?
答案 0 :(得分:0)
我没有在Ruby中调试过这种问题,但我可以给出一些一般性的建议。正如您所发现的,Ruby的mark and sweep garbage collection可能无法预测。在最好的时候调试内存问题可能会非常令人沮丧,但是当你无法可靠地重现bug时,调试起来就更难了。幸运的是,有一些事情需要深入研究。
首先,垃圾收集错误通常与大量内存分配相关联。 GC会被许多物体绊倒,或者存在泄漏内存的错误。在任何一种情况下,使用GC.stat
来收集有关处理中各个点的内存状态的信息。如果您看到内存分配不断增长,您可以开始缩小内存分析器(例如this one)可能出现的问题的范围。如果你能找到吃东西的地方,你就有了一个可以开始的地方。也许避免引入导致问题的宝石或改变存储数据的方式。
接下来,考虑调整garbage collection parameters。这不会帮助您找到错误的原因,但它可以防止它发生。可以找到GC.stat
的输出的相当广泛的调查以及可以调整的环境变量的含义in this post。
它对manually initiate GC也有帮助。如果在处理中有一点不会有一点减速,那就收集垃圾以使堆保持在可管理的水平。显然,这可能掩盖了潜在的问题,并减慢了您的应用程序。所以要谨慎使用。但是如果你找不到错误的根本原因,最好避免崩溃或者使崩溃更具可重复性。
最后,您可以尝试alternative malloc
implementation。如果您不介意从源代码构建Ruby,可以很容易地替换C编译器提供的默认malloc
并尝试其他方法。同样,它可能会掩盖潜在的问题。