在 Forge - 分析 Rails 应用程序
我于 2008 年 5 月中旬撰写本文,几周前有传言称 Twitter 将迁移到 Ruby on Rails 以外的平台。当然,Twitter 是一项非常受欢迎的服务,用户可以编写关于他们当前状态的更新和笔记,并允许读者关注任意数量的人的 Twitter 信息流。您可以将 Twitter 视为博客和 RSS 平台的结合,由每次仅用 140 个字符表达自己的人们填充。
像许多其他失控的互联网成功案例一样,Twitter 似乎因其自身受欢迎而变得不堪重负。这导致了一些中断,最值得注意的是 2008 年初的一次中断,恢复时间超过一天。因此,当 Twitter 的首席架构师离开公司,并在几天之内,TechCrunch 博客引用 Twitter 内部匿名官员的话说,该服务将从 Ruby on Rails 转型时,这被认为不仅仅是一个巧合。
随后引发了关于 Rails 是否是“可扩展”架构的大量讨论。“可扩展”过去指的是可以使用网站扩展应用程序,几乎不受使用人数的影响。但如今,可扩展的架构是指精简高效的架构,以尽可能少的服务器处理尽可能多的用户。PHP、Java 和 .NET 在这种意义上被普遍认为是可扩展的。尽管即使是最有效的 PHP 应用程序也只能处理有限数量的并发用户,但不可否认的是,Ruby 是一种比 PHP 慢的语言,并且 Rails 框架增加了一些额外的开销。
当然,说 Rails 的扩展速度不如 PHP 快是一回事,说它根本无法扩展又是另一回事。而且,还有其他论点可以提出,包括程序员的成本高于服务器,以及程序员的生产力应该至少与可扩展性一样重要。
话虽如此,Rails 应用程序很容易变得缓慢。因此,很高兴知道可以使用各种实用程序来分析 Rails 应用程序——意思是,找出程序中哪个部分执行时间过长。本月,我们将研究一些分析 Rails 应用程序的技术。尽管这种分析不会使软件运行得更快,但它可以帮助识别应用程序中最慢的部分。
如果您对网站的性能不满意——坦率地说,您应该始终关注性能,并尽可能地尝试提升性能——首先要问的问题是:“人们把时间花在哪里了?” 毕竟,如果您的网站上有 100 个不同的页面,那么如果没人访问第 35 页,那么第 35 页是否真的很慢就无关紧要了。
要检查的第一个工具是生产日志分析器,它旨在查看 Rails 生产日志并生成一些关于它的基本统计信息。生产日志以及开发和测试日志通常存储在 Rails 项目根目录下的 log 目录中。因此,在生产服务器上,日志位于 log/production.log 中。此日志文件不会自动轮换或修改;显然有很多方法可以使用 cron 和其他 UNIX 命令行工具来做到这一点。
问题是,UNIX(和 Linux)系统上已经有一个处理日志文件的工具,包括它们的定期轮换和处置。此工具称为 syslog,它允许根据优先级和源材料将日志信息发送到各种不同的文件。我的 Ubuntu 服务器上的 /var/log 目录中充满了不同的日志文件,几乎所有这些文件都是由 syslog 创建和写入的。
事实证明,我们可以将 syslog 用于我们的 Rails 生产日志。一旦我们这样做了——是的,我们必须使用 syslog 才能使其工作——我们就可以分析我们的生产日志,准确地了解人们在我们的 Rails 应用程序中花费了多少时间。
要将您的 Rails 生产日志移动到 syslog,您需要执行几个操作。首先,您必须安装提供此行为的 Ruby gem
gem install --remote SyslogLogger
这会将 gem 安装到您系统上的适当位置;在我的系统上,它被放入 /usr/lib/ruby/gems/1.8/gem 中。接下来,您需要将以下内容添加到您的一个或多个环境配置文件(environment.rb 或 environments/*.rb 中的一个或多个文件)中,用于您的 Rails 系统
require 'syslog_logger' RAILS_DEFAULT_LOGGER = SyslogLogger.new
当然,这会加载 syslog_logger gem 并将默认记录器设置为 SyslogLogger 的新实例。
现在您已经告诉 Rails 使用 syslog,您必须告诉 syslog 如何处理来自 Rails 的文件。我打开了 /etc/syslog.conf 并在底部添加了以下行
*.info /var/log/production.log
是的,文档系统说您可以在此行之前使用 !rails 标签,或类似标签,以将日志记录限制为来自 Rails 的消息。不幸的是,Linux 似乎不支持此语法。因此,这意味着 production.log 将包含来自其他程序和设施的消息,而不仅仅是 Rails。这现在不应该让我们担心,尽管在具有许多活动服务的繁忙机器上,这可能是一个问题。
以这种方式修改 syslog.conf 后,您可以重新启动 syslog.conf。几乎立即,您的生产日志应该存储到 /var/log/production.log。当然,您可以使用以下命令检查这一点
tail -f /var/log/production.log
现在,此日志文件在许多方面类似于您刚刚从应用程序根目录的 log 目录中删除的日志文件。但是,它的格式使生产日志分析器能够找到并根据其输出执行计算。要分析日志文件,请输入
pl_analyze /var/log/production_log
如果您希望通过电子邮件将结果发送给您,而不是存储到磁盘文件,请使用 -e 选项
pl_analyze /var/log/production_log -e reuven@lerner.co.il
例如,当您从 cron 作业调用 pl_analyze 时,此选项特别有用。
pl_analyze 的输出文件分为三个部分
每个请求花费的时间。
每个请求在数据库中花费的时间。
渲染每个请求的输出所花费的时间。
对于每个控制器操作,pl_request 列出了它被调用的次数,以及执行所需的平均时间。它还给出了最小值、最大值和标准偏差,让您了解执行时间随时间变化的程度。
因此,生产日志分析器显示哪些操作总体上花费的时间最多,哪些操作在数据库中(或渲染时)花费的时间最多,以及每个操作被调用的次数。
我发现 pl_analyzer 是一个不可或缺的工具,当我想确定网站是否足够快以及我应该将注意力集中在哪里以提高其速度时。
生产日志分析器显示哪些操作需要关注,但它没有说明为什么特定操作可能会给您带来麻烦。为此,您需要更深入地研究应用程序,分析的不是一组操作,而是一个特定的操作。
这要归功于 Rails 自带的内置脚本 script/performance/request。此脚本遵循用(可能很短的)Ruby 程序编写的一组指令,使用一组类似于集成测试可用的命令和子例程。
换句话说,您可以使用集成测试语法来描述一个或多个操作的简短序列,并通过请求分析器运行此程序。然后,请求分析器生成两个输出文件,描述在服务这些请求时幕后发生的事情。此信息可以帮助您提高此特定操作的性能。
为了使此脚本工作,首先安装 ruby-prof gem
gem install --remote ruby-prof
安装完成后,您需要创建一个简单的集成测试脚本。此脚本不需要包装在集成测试本身使用的同一对象中。相反,只需创建一个名为 test.rb 的文件,并将其放在文件系统上的某个位置。我创建了一个名为 test/performance 的目录并将其放在那里,内容只有一行,如下所示
get('/')
请注意,我在这里使用的是 URL,而不是控制器和操作的名称。最后,有了这个,调用分析器
script/performance/request -n 10 test/performance/test.rb
现在您应该看到程序告诉您它正在预热,然后在遍历您指定的每次迭代时进行报告。在上面的示例中,-n 10 选项指示脚本应调用的次数;默认情况下,它是 100。
请注意,输出文件放在 test 目录中(默认情况下您可能没有写入权限)。而且,实际上,输出文件非常有用,但您第一次查看它们时可能会感到困惑。
第一个输出文件 profile-output.txt 是(顾名思义)一个文本文件,显示每个方法花费了多少时间,包括时间度量和占总运行时间的百分比。考虑以下内容
%self total self wait child calls name 13.74 58.35 38.13 0.00 20.22 608720 Buffer#read
这意味着在测试期间对 Buffer#read 进行了 608,720 次调用,总共花费了 38.13 秒,或占执行时间的 13.75%。因为这是一个内置方法,所以您无法优化它。但是,您可以尝试减少调用它的次数,以便它花费更少的时间。
问题是,我们如何知道哪些函数正在调用 Buffer#read?也许从缓冲区读取是 Web 应用程序不可避免的一部分,我们只需要意识到这一点?
如果您查看第二个文件 profile-graph.html,您会看到一个很好地链接的描述,说明哪些方法调用了哪些其他方法,以及花费了多长时间。每个框代表对一个方法的分析,并且正在分析的方法以粗体打印。
粗体方法名称上方的所有方法都是父方法(即,调用了所讨论的方法的方法);而当前方法下方的方法是子方法(即,被正在分析的方法调用的方法)。通过查看谁调用了 Buffer#read,您可以查看哪些方法(如果有)需要优化或减少调用次数。通过在方法、它们的父方法和源代码之间来回查看,您可以减少大量浪费,使您的网站比以前更有效率。
本月,我们研究了程序员可以用来识别基于 Rails 的网站中的性能问题的两个基本分析工具。当然,我们还可以使用其他工具,但这些工具与 Rails 集成得如此之好,使我们更有可能使用它们。通过不断的监控和调整,我们可以使我们的网站运行得更快,而无需购买额外的服务器。
资源
The Rails Way,作者 Obie Fernandez,已成为我的最爱,因为它包含如此多的有用信息以及代码示例。它并没有试图教你 Rails,但它确实提供了大量对高级用户以及新手都有用的信息。
Advanced Rails,作者 Brad Ediger,对几个主题进行了更深入的探讨,例如性能优化、ActiveRecord 功能、RESTful 站点和国际化等。
Rails 分析器工具:这是一组工具,可以帮助您更好地了解您的基于 Rails 的站点。生产日志分析器是 Rails 分析工具集的一部分;有关更多信息,请参见 rails-analyzer.rubyforge.org。
Reuven M. Lerner,一位长期的 Web/数据库开发人员和顾问,是西北大学学习科学博士候选人,研究在线学习社区。在芝加哥地区生活四年后,他最近(与他的妻子和三个孩子)返回他们在以色列莫迪因的家。