【问题标题】:How to speed up view rendering on rails 5?如何加快 Rails 5 上的视图渲染?
【发布时间】:2017-05-25 15:28:00
【问题描述】:

我有一个带有名为 Sensor Registry 的模型的 Rails 5 应用程序。

它目前有大约 160,000 条记录,但我在尝试显示这些数据时遇到了极短的加载时间。

应用程序在双核 Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz 和 2GB RAM 上运行。

服务器日志显示如下:

于 2017-01-10 23:43:41 +0000 开始为 187.220.30.180 获取“/sensor_registries”

无法从 187.220.30.180 渲染控制台!允许的网络:127.0.0.1、::1、127.0.0.0/127.255.255.255

ActiveRecord::SchemaMigration 加载 (1.2ms) SELECT "schema_migrations".* FROM "schema_migrations"

由 SensorRegistriesController#index 处理为 HTML 在 layouts/application 中渲染 sensor_registries/index.html.erb

SensorRegistry 负载 (604.0ms) SELECT "sensor_registries".* FROM "sensor_registries"

传感器负载 (0.6ms) SELECT "sensors".* FROM "sensors" WHERE "sensors"."id" IN (49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59 , 60, 65, 61, 63, 64, 62)

在布局/应用程序中渲染 sensor_registries/index.html.erb (54663.9ms) 在 55468 毫秒内完成 200 OK(查看次数:54827.7 毫秒 | ActiveRecord:611.5 毫秒)

我摆脱了 N+1 问题,但我想知道我是否可以对数据库查询做更多的事情。

反正问题似乎是在渲染页面的那一刻,处理它大约需要 54 秒。

有没有办法优化 CPU 使用率?

什么是加快流程并以足够快的速度向用户显示数据的最佳解决方案?

【问题讨论】:

  • 如果没有具体的应用知识,这是一个很难回答的问题。但是,您需要分析您的操作并查看可以改进慢速部分的地方。 NewRelicRequestProfiler/KCachegrind 这样的工具对这类事情很有用。
  • 我只是想知道为什么需要显示 160k 条记录,以及用户如何在一个巨大的滚动页面上查看所有这些记录。
  • 你能发布控制器并查看源代码吗?
  • 通常,这是一个与代码相关的问题,您应该检查视图上是否调用了 n+1 个查询,或者可以避免的代码重复

标签: ruby-on-rails ruby postgresql


【解决方案1】:

使用分页或其他方式(最多 5-10 条)减少同时显示的记录数量。这样您的查询和渲染将大大减少。我更喜欢 will_paginate gem,但还有更多。

在您的视图中,减少用于渲染每个传感器并为单个传感器创建单独视图(显示)的逻辑量。在单个传感器视图中,您可以添加更多逻辑。

使用新的 Relic gem 来监控您的应用并查看哪个请求花费的时间最多。也许您的外部资源很慢,例如 api 调用等,您可以通过 Ajax 而不是在服务器上执行这些资源:https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-installation

这些是基础,一旦你完成了这些,就可以继续进行预加载和缓存。

对于急切加载,请阅读:http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

关于缓存请阅读 DHH 的博文:https://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works

【讨论】:

    【解决方案2】:

    这当然看起来不像是硬件问题,而是实施方面的问题。如果不进一步了解您的数据结构和架构,这是不可能完美回答的,但有一些想法可以帮助您找出问题所在:

    1) 渲染的页面有多大?数据的绝对大小是否有可能导致渲染时间变慢?如果这是问题所在并且呈现的页面太大,请考虑对结果进行分页。

    2) ruby​​ 进程在任何时候都使用多少内存?当您说它“有大约 160,000 条记录”时,我假设您正在谈论 sensor_registries 表,并且我假设带有 sensors.id in (...) 位的后续传感器查询是使用 sensor_registries 表中的一些数据构建的。如果在完成任何进一步的工作之前将整个表加载到内存中,那么 ruby​​ 进程是否可能只是内存不足?

    3) 另外,整个表真的需要一次全部加载吗?您可能想看看http://apidock.com/rails/ActiveRecord/Batches/find_in_batches。这种方法非常适合分解需要在大桌子上完成的工作。

    4) 甚至更好——实际上没有更好的方式来表达这一点——重新考虑你的架构。作为同步请求的一部分(即使是很小的请求)在内存中加载整个表几乎总是禁忌。你能想出一个 sql 查询来获取所有需要的记录而不加载整个表吗?

    5) 如果您绝对需要整个表,那么在一次加载后缓存结果怎么样?如果您希望查询的结果在具有相同参数的请求之间是相同的,您是否可以从参数中构造一个缓存键,并使用它来存储结果?至少这样,第一个请求之后的所有请求都会很快(呃)。

    【讨论】:

      【解决方案3】:

      用户遵循的方法:

      • 用户分页以在页面上显示限制记录数并在单击按钮时加载更多记录。
      • 用户页面缓存将数据放入缓存并在更短的时间内加载繁重的页面。
      • 页面加载后加载js文件,使用压缩js文件。

      【讨论】:

      • 遵循 DRY 原则做胖模型瘦控制器。
      猜你喜欢
      • 2023-04-09
      • 1970-01-01
      • 2014-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 2010-11-09
      相关资源
      最近更新 更多