【问题标题】:Ruby on Rails site slow/downRuby on Rails 网站变慢/变慢
【发布时间】:2014-09-27 03:44:14
【问题描述】:

我正在接管一个 Ruby on Rails 站点,我发现该站点存在巨大的性能问题。有时该网站甚至没有加载。这对网站来说并不新鲜。

它位于具有 2gb 内存的 Rackspace 服务器(第一代)上。

它使用 Apache2 和 MySQL 在 Ubuntu Hardy 上运行。 RoR 站点运行的是旧版本的 Ruby (1.8.7) 和 Rails (3.2.1)。

根据 top(shift m),Apache(res 列)每个进程使用大约 6mb 到 10mb。

它使用具有以下规格的 prefork mpm: 启动服务器 2 MinSpareServers 2 MaxSpareServers 2 最大客户数 50 MaxRequestsPerChild 100

Passenger 设置为: 乘客最大池大小 10

Passenger-memory-stats 显示 Rails 平均使用大约 40mb。

free -ml 始终显示 100mb 到 1500mb 的可用内存。

Passenger-status 有时会在全局队列等待中显示高达 250,但通常在 0 到 100 之间变化。

我尝试过使用 MaxClients 和 PoolSize,但最终该网站会因速度缓慢或在某些时候根本无法访问,但我假设当流量缓解时,稍后可能会再次正常加载。

加载实际的 Rails 站点有时可能需要很长时间,但加载静态文件(图像、txt 文件)可以正常工作。虽然有时它会导致您甚至无法加载静态文件。

关于尝试使其正常工作的任何指示?对于它获得的流量(每月大约 25 万次展示),服务器似乎适合这个网站。

编辑: 尽管我还是把它放在这里,但我还是回复了 cmets。

数据库大小约为 1gb。有相当多的垃圾邮件问题(新帐户是明显的垃圾邮件,平均每天大约 1k,垃圾邮件帖子/cmets 等)。到目前为止,Mysql-slow.log 没有显示任何内容。

感谢所有 cmets。我曾希望这只是我在 Apache 或Passenger 服务器设置上的白痴。我的下一步是开始调查代码和查询。

【问题讨论】:

  • 您在处理大量数据吗?还是密集查询?空数据库也一样慢吗?
  • 哪些页面似乎导致了最大的问题?必须分析正在运行的查询?我知道我在使用n+1 查询嵌套资源时遇到了巨大的性能影响。我只需要完全重构多个控制器和模型来缓解这些在小型开发环境中不会发生的问题,因为资源要小得多
  • 开始调查应用程序本身以找出它在做什么。我想响应时间很短。这就是乘客排队堆积的原因。
  • 调查应用程序和查询是我的下一步,但我希望它可能只是我搞砸了一些 apache 或乘客设置。我启用了慢速 mysql 日志,但它是空的。我不确定它是否是导致问题的单个特定页面。当它变慢时,整个网站都会变慢。有时它会减慢到加载静态文件不再起作用的程度(apache 崩溃?)。但除此之外,该网站非常活泼,加载时间也很好。有关试图找出导致此问题的页面的任何指针?

标签: ruby-on-rails ruby performance apache


【解决方案1】:

在了解不多的情况下,我只能提供更一般的建议。为了提高网站性能,请记住the Perfomance Golden Rule

80-90% 的最终用户响应时间花费在前端。从那里开始。

下面是非详尽的列表,可以提高 Rails 应用程序的性能:

诊断慢速 Rails 应用程序:

Y 慢

用于识别性能问题的有用诊断工具是Yslow。它是一个浏览器扩展程序,可以诊断和识别降低应用程序速度的常见问题(尤其是在前端)。

后端工具

对于您的 Rails 后端,我建议将 BulletNewRelic 等工具直接集成到您的开发过程中,这样您在开发时可以立即发现错误查询,同时它们仍然很容易修复。

检查服务器控制台日志

检查服务器日志是诊断 Rails 应用程序的哪些组件占用时间最长的有效方法。例如。下面是在我的本地开发环境中运行的两个不相关的生产 Rails 应用程序的示例日志(不包括庞大的数据库 i/o 部分):

# app1: slowish
  Rendered shared/_header.html.erb (125.9ms)
  Rendered clients/details.html.erb within layouts/application (804.6ms)
  Completed 200 OK in 3655ms (Views: 566.9ms | ActiveRecord: 1236.9ms)

# app2: debilitatingly slow
  Rendered search/_livesearch_division_content.js.erb (5390.0ms)
  Rendered search/livesearch.js.haml (34156.6ms)
  Completed 200 OK in 34173ms (Views: 31229.5ms | ActiveRecord: 2933.4ms)

App1 和 App2 都存在性能问题,但 App2 的性能问题显然非常缓慢。 但是有了这些服务器日志,我知道 App1 应该查看 clients/details.html.erb,而对于App2 我绝对需要调查search/livesearch.js.haml。 (我发现 App2 对大量数据有未缓存的大型 N+1 查询——我稍后会谈到)

提高前端性能

预算你的页面大小严格

要保持快速加载时间,您需要减少页面资源(JS/CSS/图像)的数量/大小。因此,将您的页面大小视为预算。例如,Hootesuite 最近宣布他们的主页现在有严格的页面大小预算 1 mb。没有例外。 Now check out their page. Pretty fast isn't it?

减少页面大小的简单方法包括去除未使用的 JS 或 CSS 文件,仅在需要时包含它们,以及将静态图像更改为更小的矢量。

根据屏幕宽度提供更小的图像分辨率

图像加载是导致页面加载时间变慢的一个重要原因。在启动页面背景中使用的 5mb 大图像可以很容易地缩小到 200kb-400kb 大小,并且仍然具有足够高的质量,与更高分辨率的原始图像几乎没有区别。页面加载时间的差异将是巨大的。

您也应该对上传的图片执行相同的操作。例如。如果用户为他的横幅或头像上传了 5mb 的图像,那么您必须以较低的文件大小/分辨率提供此上传的图像,具体取决于它将显示的大小。 CarrierwaveFogrmagickminimagic 结合使用是一种流行的技术,用于 Amazon S3 以实现更好的图像上传/调整大小。使用它们,您可以动态地提供较小的图像分辨率以适应用户的屏幕尺寸。然后,您可以使用媒体查询来确保为移动设备提供比配备 Retina 屏幕的台式机更小的图像分辨率和文件大小。

使用内容交付网络加速资产加载

如果您的网站处理大量图像或大文件,那么您应该考虑使用 Cloudfront 等内容交付网络 (CDN) 来加快资产/图像加载时间。 CDN 将您的资产文件分布在世界各地的许多服务器上,然后使用最接近用户地理区域的服务器来提供资产。除了更快的速度之外,CDN 的另一个好处是它可以减少您自己的服务器上的负载。

指纹静态资源

对静态资产进行指纹识别后,当用户访问您的页面时,他们的浏览器将缓存这些资产的副本,这意味着它们不再需要为下一次请求重新加载。

将 Javascript 文件移动到页面底部

如果在不使用 Rails 方式的情况下包含其他 javascript 文件,请注意,如果将 javascript 资源放置在页面顶部,则页面在加载时将保持空白,而用户的浏览器尝试加载它们。如果您使用资产管道或使用 javascript_include_tag 指定 javascript 文件以防止此问题,Rails 将自动将 javascript 文件放置到页面底部,但如果不是这种情况,请确保外部 Javascript 文件包含在底部这页纸。

提高后端性能

缓存、缓存、缓存(使用 Memcache/Dalli)!

在后端性能优化中,没有任何一项性能增强可以与缓存提供的优势相媲美。缓存是将任何 Rails 应用程序推向高可伸缩性的重要组成部分。一个实施良好的缓存机制极大地减少了服务器对低效查询的暴露,并且可以减少对现有的非性能代码进行痛苦的重构的需要。

以我上面提到的 App2 示例为例,在我们实现了一个简单的页面缓存后,我们的 34 秒 页面加载时间下降到 不到一秒 在生产中。 我们没有重构此代码的任何一行。

经常访问但相对不经常更改的页面内容最容易缓存并从缓存中受益最多。在服务器端有多种缓存方式,包括页面缓存和片段缓存。 Russian doll caching 现在是 Rails 中最受欢迎的片段缓存技术。 Here's a good place to start.

索引(几乎)一切

如果您在数据库层使用 SQL,请确保在连接表上指定索引,以便更快地查找经常使用的大型关联。您必须在迁移期间明确添加它们,因为indexing is not included by default in Rails.

使用 Eager Loading 消除 N+1 个查询

使用关系 (SQL) 数据库的 Rails 应用程序的主要性能杀手是 N+1 queries。如果您在日志中看到以类似于模式的方式对单个请求进行数百次数据库读取/写入,那么您很可能已经遇到了严重的 N+1 查询问题。 N+1 查询在开发过程中很容易遗漏,但会随着数据库的增长而迅速削弱您的应用程序(我曾经处理过一个有 12 个 N+1 查询的问题。在积累了大约 1000 行生产数据后,一些页面开始占用 超过一分钟加载)。

Bulletcatching N+1 queries early as you develop your app. 的绝佳选择。在 Rails 应用程序中解决 N+1 查询的简单方法是在必要时预先加载关联的模型。例如。如果您正在加载页面上每个帖子的所有 cmets,Post.all 将更改为 Post.includes(:comments).all

升级到 Rails 4 和/或 Ruby 2.1.x 或更高版本

较新版本的 Rails 包含许多性能改进,可以加快您的应用程序(例如 Turbolinks)。如果您仍在运行 Rails 3.2.1,那么您需要至少升级到 Rails 3.2 .18 仅出于安全原因。

Ruby 2.1.x+ 包含比旧版本的 Ruby 更好的垃圾收集。目前已经发现有人升级的报道notable performance increases from upgrading.


我可以推荐一些性能改进。如果没有更多信息,我就帮不上什么忙了。

【讨论】:

    【解决方案2】:

    仅索引正常访问的模型。这也应该会给您带来显着的性能提升。

    【讨论】:

      猜你喜欢
      • 2010-10-08
      • 2018-11-27
      • 2010-12-29
      • 1970-01-01
      • 2011-02-19
      • 2012-10-01
      • 2017-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多