如何调试花费太多时间才能完成的请求?
How to debug requests taking too much time to complete?
XHR 请求随机需要花费太多时间才能完成。而且我找不到发生这种情况的地方。如果有的话。当我围绕可疑的 ruby 代码块启用探查器时,其他地方发生了劫持。但是,我无法用 webrick
重现它。有什么想法吗?
UPD 这是一个 rails 应用程序,使用 sequel 连接到 postgresql。 Here are 有关我所面临问题的详细信息。
这是我所做的:
1) 在/usr/lib/ruby/vendor_ruby/phusion_passenger/rack/thread_handler_extension.rb
开头添加了如下代码:
def __l *args
File.open('/home/USER/' + Process.pid.to_s + '.log', 'a') { |f| f.puts *args }
end
require 'ruby-prof'
def __start_profiler
RubyProf.start
if false
require 'profiler'
$old_compile_option = RubyVM::InstructionSequence.compile_option.select { |k, v|
[:trace_instruction, :specialized_instruction].include? k
}
RubyVM::InstructionSequence.compile_option = {
:trace_instruction => true,
:specialized_instruction => false
}
Profiler__::start_profile
end
end
def __get_profiler_output
sio = StringIO.new
result = RubyProf.stop
# printer = RubyProf::GraphPrinter.new(result)
printer = RubyProf::FlatPrinter.new(result)
printer.print(sio)
return sio.string
if false
Profiler__::print_profile(sio)
RubyVM::InstructionSequence.compile_option = $old_compile_option
sio.string
end
end
2) 在process_action
方法开头添加如下代码:
__start = Time.now
__l '-' * 80, __start, env['REQUEST_URI'], env['HTTP_X_REAL_IP']
__start_profiler
3) 将方法末尾的大 begin...end
块的结果放入 r
变量
4) 在方法末尾添加如下代码:
__r = __get_profiler_output
if Time.now - __start > 10
__l 'profiler'
__l __r
__l 'profiler'
end
__l 'elapsed: %g: %s' % [Time.now - __start, env['REQUEST_URI']], '-' * 80
r
5) 每次测试前运行:
rm -f ~/*.log && touch tmp/restart.txt && watch 'grep elapsed ~/*.log | sort -gr -k2 | head'
并且能够找到罪魁祸首:
%self total self wait child calls name
99.92 65.713 65.713 0.000 0.000 5 PG::Connection#async_exec
0.00 0.002 0.002 0.000 0.000 264 Set#delete
...
XHR 请求随机需要花费太多时间才能完成。而且我找不到发生这种情况的地方。如果有的话。当我围绕可疑的 ruby 代码块启用探查器时,其他地方发生了劫持。但是,我无法用 webrick
重现它。有什么想法吗?
UPD 这是一个 rails 应用程序,使用 sequel 连接到 postgresql。 Here are
这是我所做的:
1) 在/usr/lib/ruby/vendor_ruby/phusion_passenger/rack/thread_handler_extension.rb
开头添加了如下代码:
def __l *args
File.open('/home/USER/' + Process.pid.to_s + '.log', 'a') { |f| f.puts *args }
end
require 'ruby-prof'
def __start_profiler
RubyProf.start
if false
require 'profiler'
$old_compile_option = RubyVM::InstructionSequence.compile_option.select { |k, v|
[:trace_instruction, :specialized_instruction].include? k
}
RubyVM::InstructionSequence.compile_option = {
:trace_instruction => true,
:specialized_instruction => false
}
Profiler__::start_profile
end
end
def __get_profiler_output
sio = StringIO.new
result = RubyProf.stop
# printer = RubyProf::GraphPrinter.new(result)
printer = RubyProf::FlatPrinter.new(result)
printer.print(sio)
return sio.string
if false
Profiler__::print_profile(sio)
RubyVM::InstructionSequence.compile_option = $old_compile_option
sio.string
end
end
2) 在process_action
方法开头添加如下代码:
__start = Time.now
__l '-' * 80, __start, env['REQUEST_URI'], env['HTTP_X_REAL_IP']
__start_profiler
3) 将方法末尾的大 begin...end
块的结果放入 r
变量
4) 在方法末尾添加如下代码:
__r = __get_profiler_output
if Time.now - __start > 10
__l 'profiler'
__l __r
__l 'profiler'
end
__l 'elapsed: %g: %s' % [Time.now - __start, env['REQUEST_URI']], '-' * 80
r
5) 每次测试前运行:
rm -f ~/*.log && touch tmp/restart.txt && watch 'grep elapsed ~/*.log | sort -gr -k2 | head'
并且能够找到罪魁祸首:
%self total self wait child calls name
99.92 65.713 65.713 0.000 0.000 5 PG::Connection#async_exec
0.00 0.002 0.002 0.000 0.000 264 Set#delete
...