我最近将一个应用程序升级到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}

08-06 02:52