Heroku、Nokogiri & Sidekiq 内存泄漏 - 如何调试?



我刚刚在Heroku上切换到使用Sidekiq,但在我的作业运行了一段时间后,我得到了以下内容:

2012-12-11T09:53:07+00:00 heroku[worker.1]: Process running mem=1037M(202.6%)
2012-12-11T09:53:07+00:00 heroku[worker.1]: Error R14 (Memory quota exceeded)
2012-12-11T09:53:28+00:00 heroku[worker.1]: Error R14 (Memory quota exceeded)
2012-12-11T09:53:28+00:00 heroku[worker.1]: Process running mem=1044M(203.9%)

它一直这样生长。

对于这些工作,我使用Nokogiri和HTTParty来检索URL并解析它们。我试着更改了一些代码,但实际上我一开始就不确定我在寻找什么。我应该如何调试它?

我试着将新遗迹添加到我的应用程序中,但不幸的是,它还不支持Sidekiq。

此外,在谷歌上搜索后,我试图切换到SAX解析器,看看它是否有效,但我被卡住了。这就是我迄今为止所做的:

class LinkParser < Nokogiri::XML::SAX::Document
def start_element(name, attrs = [])
if name == 'a'
puts Hash[attrs]['href']
end
end
end

然后我尝试了一些类似的东西:

page = HTTParty.get("http://site.com")
parser = Nokogiri::XML::SAX::Parser.new(LinkParser.new)

然后,我尝试使用以下方法处理我使用HTTParty检索到的数据,但未能使这些方法中的任何一种正确工作:

parser.parse(File.read(ARGV[0], 'rb'))
parser.parse_file(filename, encoding = 'UTF-8')
parser.parse_memory(data, encoding = 'UTF-8') 

更新

我发现解析器不起作用,因为我调用的是parser.parse(page)而不是parser.parse(page.body)。然而,我已经尝试使用上面的脚本打印出各种网站的所有html标签,对于一些网站,它打印出所有标签,而对于其他网站,它只打印出几个标签

如果我使用Nokogiri::HTML()而不是parser.parse(),效果很好

我在HTML文档中使用Nokogiri::XML::SAX::Parser.new()而不是Nokogiri::HTML::SAX::Parser.new(),这就是我遇到麻烦的原因。

代码更新

好的,我现在已经有了下面的代码,但不知道如何将我得到的数据放入一个数组中,我以后可以使用…

require 'nokogiri'
class LinkParser < Nokogiri::XML::SAX::Document
attr_accessor :link
def initialize
@link = false
end
def start_element(name, attrs = [])
url = Hash[attrs]
if name == 'a' && url['href'] && url['href'].starts_with?("http")
@link = true 
puts url['href']
puts url['rel']
end
end
def characters(anchor)
puts anchor if @link
end
def end_element(name)
@link = false
end
def self.starts_with?(prefix)
prefix.respond_to?(:to_str) && self[0, prefix.length] == prefix
end
end

最后,我发现内存泄漏是由于"Typhoeus"gem引起的,它是我在部分代码中使用的"PageRanker"gem的依赖项。

我发现这一点的方法是在本地运行代码,同时使用watch "ps u -C ruby"监控内存使用情况,然后测试代码的不同部分,直到我能够确定内存泄漏的来源。

我将此标记为已接受的答案,因为在最初的问题中,我不知道如何调试内存泄漏,但有人告诉我要执行上述操作,结果成功了。

万一你不能解决gems内存泄漏问题:

您可以在forks中运行sidekiq作业,如答案中所述https://stackoverflow.com/a/1076445/3675705

只需添加应用程序助手"do_in_child",然后在您的工作中

def perform
do_in_child do
# some polluted task
end
end

是的,我知道这是一个肮脏的解决方案,因为Sidekiq应该在线程中工作,但在我的情况下,它是唯一一个快速的生产解决方案,原因是我在解析nokogiri的大XML文件时工作很慢。

"快速"线程功能不会带来任何优势,但内存泄漏让我在工作10分钟后可以处理2GB+的主sidekiq进程。一天后,sidekiq虚拟内存增长到11GB(我的服务器上所有可用的虚拟内存),所有任务都非常缓慢。

相关内容

  • 没有找到相关文章

最新更新