我最近将一个应用程序升级到Rails 2.2.2。完成此操作后,我遇到了一个奇怪的性能错误,该错误已导致通常在不到一秒钟的时间内完成渲染的渲染最多需要10秒钟。
我已经解决了这个问题,并且here are the results I've come up with。看来问题出在Mysql类的real_connect
方法中。我的理解是Ruby real_connect
方法是C mysql_real_connect()
函数的包装。这会让我相信问题一定出在数据库上,因为在Windows和Linux(数据库服务器是一个单独的系统)上运行代码时,我遇到了同样的问题。但是,我不相信这种情况,因为当我从Subversion版本库回滚到以前的版本(Rails 2.2.2之前的版本)时,性能问题就消失了。这似乎表明ActiveRecord中存在某种错误。
我该如何识别并修复此错误?有人有见识吗?有什么我想念的吗?
更新:我只是创建了一个小的探查器脚本来测试Mysql.real_connect方法,看来问题出在Rails中,而不是MySQL gem或数据库服务器本身。
运行以下代码后:
result = RubyProf.profile do
5.times do
begin
# connect to the MySQL server
dbh = Mysql.real_connect(ip, user, pass, db)
# get server version string and display it
puts "Server version: " + dbh.get_server_info
rescue Mysql::Error => e
puts "Error code: #{e.errno}"
puts "Error message: #{e.error}"
puts "Error SQLSTATE: #{e.sqlstate}" if e.respond_to?("sqlstate")
ensure
# disconnect from server
dbh.close if dbh
end
end
end
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT, 0)
我想出了这个性能结果:
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Thread ID: 18998180
Total: 50.402000
%self total self wait child calls name
99.99 50.40 50.40 0.00 0.00 5 <Class::Mysql>#real_connect (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 10 IO#write (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Mysql#get_server_info (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Kernel#puts (ruby_runtime: 0}
0.00 0.00 0.00 0.00 0.00 5 String#+ (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Mysql#initialize (ruby_runtime:0}
0.00 50.40 0.00 0.00 50.40 1 Integer#times (ruby_runtime:0}
0.00 50.40 0.00 0.00 50.40 1 Global#[No method] (tmp/mysql_test/test.rb:12}
0.00 0.00 0.00 0.00 0.00 5 Mysql#close (ruby_runtime: 0}
看来问题出在ActiveRecord上,而不是MySQL gem或数据库中。我从这里去哪里?
最佳答案
我能够找到问题所在。我首先从开发计算机上使用命令mysql --host=ip --user=user --password=password db
使用MySQL命令连接到主机。这非常慢,所以我将服务器切入服务器,并使用相同的命令从那里连接。这也很慢。
我将命令更改为mysql --host=localhost --user=user --password=password db
,并且可以立即连接。我在/etc/hosts
文件中为我的开发系统添加了一个条目,并且也能够从该实例即时连接。显然,MySQL服务器正尝试执行反向DNS查找来解析与IP地址关联的主机名(如MySQL Manual中所列),并且正在超时。
我在/etc/init.d/mysql脚本的开始部分添加了--skip-name-resolve
选项,以便跳过此检查,然后重新启动服务器。运行先前创建的配置文件脚本时,得到以下结果:
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Server version: 5.0.32-Debian_7etch3-log
Thread ID: 52978590
Total: 0.016000
%self total self wait child calls name
87.50 0.01 0.01 0.00 0.00 5 <Class::Mysql>#real_connect (ruby_runtime:0}
6.25 0.00 0.00 0.00 0.00 10 IO#write (ruby_runtime:0}
6.25 0.00 0.00 0.00 0.00 5 Mysql#close (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Kernel#puts (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Mysql#initialize (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 String#+ (ruby_runtime:0}
0.00 0.02 0.00 0.00 0.02 1 Global#[No method] (tmp/mysql_test/test.rb:12}
0.00 0.02 0.00 0.00 0.02 1 Integer#times (ruby_runtime:0}
0.00 0.00 0.00 0.00 0.00 5 Mysql#get_server_info (ruby_runtime:0}