我最近将我的一个应用程序升级到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存储库回滚到以前的版本(pre 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或数据库中。我从哪里开始?
答案 0 :(得分:1)
我能够找到问题所在。我首先使用命令mysql --host=ip --user=user --password=password db
使用我的开发机器上的MySQL命令连接到主机。这非常慢,所以我进入服务器,并使用相同的命令从那里连接。这也很慢。
我将命令更改为mysql --host=localhost --user=user --password=password db
,我能够即时连接。我在/etc/hosts
文件中为我的开发系统添加了一个条目,并且能够即时连接。显然,MySQL服务器正在尝试执行反向dns查找以解析与IP地址关联的主机名,如MySQL Manual中所列,并且已超时。
我将--skip-name-resolve
选项添加到/etc/init.d/mysql脚本的start部分,以便跳过此检查,然后重新启动服务器。当我运行之前创建的配置文件脚本时,我得到以下结果:
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}