如何提升 RailS 应用的性能?

Is rails slow?

「铁路很慢」,你也许听过这个笑话,那么我们的 Rails 框架呢?

如果说 Rails 慢,那么如何提升 Rails APP 的性能就成了开发者们最关注的问题。

也许你听说过很多提升 RoR APP 性能的方法,它们有难有易,我们需要在选择其中最能帮助开发者脱离性能困境的。

这里列举了几种不同的提升 Rails 应用性能的方法。

1. 数据库索引

你的 APP 被 DB 性能限制,优秀的数据库索引可以在大型数据库表中带给你100倍的性能提升。然而并非所有 Rails 开发者都明白这一点有多重要。

添加 indexes 很容易:

class AddIndexToClientIndustry < ActiveRecord::Migration
    def change
        add_index :client_industries, :client_id
    end
end

接下来就有无 Index 的情况做个对比。

有 Index 的情况:

CREATE INDEX
addresses_addressable_id_addressable_type_idx  ON
addresses  USING btree  (addressable_id,addressable_type);
t1 = Time.now
 c = Company.find(178389)
 a = c.addresses.first
t2 = Time.now
puts "---Operation took #{t2-t1} seconds---”

Result with index:
---Operation took 0.012412 seconds---

没有 Index 的情况:

DROP INDEX
addresses_addressable_id_addressable_type_idx;

t1 = Time.now
 c = Company.find(178389)
 a = c.addresses.first
t2 = Time.now
puts "---Operation took #{t2-t1} seconds---”

Result without index:
---Operation took 0.378073 seconds---

0.378073 / 0.012412 = 30.46 没有索引比有索引慢了30.46秒。

因此工程师可以在所有引用参数,或者其他经常查询的参数中加入 Indexes。但是不能加太多, 因为每一个都会增加 DB Size 从而影响性能。

2. 数据库查询数量

RoR让编程更快捷,但反过来也让每条请求的数据库查询次数难以控制。举个例子,如果每一个 Client 有一或多个 Industries。 我们想要显示 Client List 和它们的 Primary Industries:

<% @clients.each do |client| %>
  <tr>
      <td><%= client.id %></td>
      <td><%= client.business_name %></td>
      <td><%= client.industries.first.name %></td>
  </tr>
<% end %>

# app/controllers/clients_controller.rb
def index
    @clients = Client.all
end

如果有50个 Clients, 则会有51条数据库查询:

    Processing by ClientsController#index as HTML
    SELECT "clients".* FROM "clients"
    SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 1 LIMIT 1
    SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 2 LIMIT 1
    SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 3 LIMIT 1
    …

解决方案: Eager Loading

# app/controllers/clients_controller.rb
def index
    @clients = Client.includes(:industries).all
end

现在只有2至3条数据库查询而非51条:

    Processing by ClientsController#index as HTML
    SELECT "clients".* FROM "clients"
    SELECT "client_industries".* FROM
    "client_industries" WHERE
    "client_industries"."client_id" IN (1, 2, 3)
    SELECT "industries".* FROM "industries" WHERE "industries"."id" IN (1, 5, 7, 8, 4)

3. 减少内存占用

  • 只用真正需要的gem
  • 使用时再加载对象
  • 分批处理海量数据。

一个使用真实数据的例子——find_each:

Using find:
t1 = Time.now
Company.where(:country_id=>1).find do |c|
puts "do something!" if [‘Mattski Test‘].include?(c.common_name)
end
t2 = Time.now
puts "---Operation took #{t2-t1} seconds---”
Result:
1 query, taking 46.65 seconds
Now using find_each:
t1 = Time.now
Company.where(:country_id=>1).find_each do |c|
    puts "do something!" if [‘Mattski Test‘].include?(c.common_name)
end
t2 = Time.now
puts "---Operation took #{t2-t1} seconds---"
Result:
100 queries, taking 15.53 seconds in total (3x faster)

也有查询多了反而快的情况。

4. 使用缓存

缓存的使用对性能有巨大影响,首先确保数据模型正确,缓存可以帮你隐藏结构问题。

  • 对象缓存

    在使用对象缓存的情况下,应该把查询方法的 include 去掉,避免关联查询无法利用缓存的现象。

  • 查询缓存

    在不要求实时的情况下,对于统计类耗时查询,那么可以使用 memcache-client 将查询结果缓存到 memcached 里。

  • 页面局部缓存

    对象缓存和查询缓存都会降低数据库访问负载,但如果 RoR 的负载很高,就只能依靠页面局部缓存了。

「web2.0网站比较常用使用页面局部缓存,Rails 的页面局部缓存有一个缺点,就是和页面查询结果对应的 Action 当中的查询语句要放在 View 里面,否则每次 Action 里面的查询还是会被执行,但是这样做会破坏程序代码良好的 MVC 结构。这种情况下,也可以采用另外一个 Cache 插件: better rails caching,在缓存页面的同时可以缓存 Action 当中的查询语句。」

5. 让 web 请求更快

只有少量可用进程用于服务 web 请求,因此需要使 web 请求更快。理想情况下, web 进程一般在毫秒内完成,1至2秒算是慢的,10秒以上是非常慢的。如果你的 web 请求很慢,你的Rails APP 将无法支撑同一时间的大量用户。

解决方案:使用后台运行

对长时间运行的项目使用后台运行诸如 delayed jobs, 从而释放你的 web 进程来解决更多请求。

6. 性能监控

对 APP 进行性能监控从而便于发现哪部分运行的慢,甚至快速定位到问题所在,可以利用国内应用性能监控做的最好的 OneAPM 监控工具。

OneAPM for Ruby 能够深入到所有 Ruby 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。 追溯性能瓶颈至:性能表现差的 SQL 语句、第三方 API、Web Services、Caching Layers、后台任务等。

图为使用 OneAPM 进行监控的总览页面,在这里可以对请求在服务器端耗时有个初步印象。可以直观的看到不同时间 web 事物、后台任务、数据库和外部服务的平响应时间、吞吐量、执行次数等指标,图中 web 事物在15:41的时候响应时间出现峰值,响应速度较慢。

为了进一步确定问题所在,点进 web 事物界面可以进一步了解各慢事物响应时间占比,快速定位到 api/medicines/index 的响应时间较长。

点击错误的请求地址,将会列出该错误的 URL、第一次和最后一次发生时间、错误发生次数、监测到错误的 Agent 名称、错误信息和堆栈信息。

好的应用性能监控往往需要花大量的时间和精力实现,因此选择优秀的第三方监控工具将极大地提高运维效率,这对提升 Rails APP 性能有极大帮助。

7. 使用内存数据库

当查询和排序都在内存中完成,数据库将会运行的更快,而它们需要在磁盘上运行的时候就变得很慢。

解决方案:

  • 限制 DB 的大小,保证它完全适合内存。
  • 将不紧急的信息移出主要数据库,移入次要数据库或其他地方。
  • 如果有大量存储需求,考虑使用非关系型数据库。

8. 更多性能建议:

  • 对静态文件使用内容分发网络,例如使用 AWS CloudFront。
  • 对需要1-2秒的加载项使用延迟加载。
  • 使用服务导向架构,使一些进程在托管栈同步进行。

相信选择一种或几种适合的性能提升方法,可以使 RoR APP 更令用户满意。

备注:本文参考并翻译了 Matt Kuklinski 在 slideshare 上关于 提升 Rails 性能所分享的部分内容。

本文系 OneAPM 工程师编译整理。OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读更多技术文章,请访问 OneAPM 官方博客

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-25 07:56:48

如何提升 RailS 应用的性能?的相关文章

How to improve Java&amp;#39;s I/O performance( 提升 java i/o 性能)

原文:http://www.javaworld.com/article/2077523/build-ci-sdlc/java-tip-26--how-to-improve-java-s-i-o-performance.html JDK 1.0.2 的 java.io 包暴露了非常多I/O性能问题.这里将介绍一个优化方案,附加一个关闭同步的方法. Java的I/O性能以前是非常多Java应用的瓶颈.主要原因就是JDK1.0.2的java.io包的不良设计和实现.关键问题是缓冲.绝大多数java.i

如何提升程序员的“性能”

程序员经常痴迷于优化程序的性能,我们始终会围绕一些让人绞尽脑汁的优化建议,比如:如何简化代码.如何提升软件运行速度.如何提高软件稳定性等等.本文来讨论一下程序员优化自身“性能”的一些建议. 1.提高文档编写能力 缺乏文档,对软件开发是致命的,一方面是软件无追溯能力,无法找到软件开发的起源,思想:另一方面,则是为后续软件查错,软件升级带来麻烦.作为早期的程序员,技术文档占用的工作时间应该为 30%,而高级程序员.系统架构师等则需更多的时间.一般的软件文档要求,本篇不多说,可以回顾入职前手头上的软件

十大技巧快速提升Android应用开发性能

一个应用程序要想开发成功,质量至关重要.用户要求它们决定安装到自己设备上的Android应用程序反应迅即.性能合理.如果应用程序未能提供好用的功能和稳定的用户体验,那么很快就会被卸载掉.本文我们将介绍十大技巧快速提升Android应用开发性能. 1:首先要有良好的编程习惯 要成为一名优秀的资源管理员;既要运用常识,还要使用公认的算法和标准的设计模式.在资源使用方面,如果你打开了资源,要记得关闭资源.要尽量晚地获取,尽量早地释放.这些由来已久的编程准则同样适用于你的Android应用程序,如果它们

How to improve Java&#39;s I/O performance( 提升 java i/o 性能)

原文:http://www.javaworld.com/article/2077523/build-ci-sdlc/java-tip-26--how-to-improve-java-s-i-o-performance.html JDK 1.0.2 的 java.io 包暴露了很多I/O性能问题,这里将介绍一个优化方案,附加一个关闭同步的方法. Java的I/O性能曾经是很多Java应用的瓶颈,主要原因就是JDK1.0.2的java.io包的不良设计和实现.关键问题是缓冲,绝大多数java.io中

网站服务器部署及优化---3---使用eAccelerator提升网站服务器的性能(rhel6.5)

RedHat Enterprise 6.5环境下使用eAccelerator优化网站性能 第一步:在做优化之前,首先对网站服务器的硬件做一下检测 1,内存信息:2G内存,swap容量为4G [[email protected] ~]# free -m total       used       free     shared    buffers     cached Mem:          1870       1228        642          0         47

移动端网站提升页面加载性能的优化技巧

移动端网站提升页面加载性能的优化技巧 收藏到:1时间:2015-06-17   文章来源:马海祥博客   访问次数:2501 网页性能的优化一直是网站成功的关键,越来越多的研究证明,不管是小型电商,还是大型连锁企业,即使是页面加载时间方面的细微改善,都可以带来更多的业务,更多的广告收入,更多的用户粘性和更多的客户满意度. 在过去几年,Web开发者都是基于改善硬件或者提高带宽速度来优化用户体验,但是最近几年,爆炸式的移动Web浏览器的使用打破了这个途径,低带宽,高延迟,小内存,低处理器性能的移动设

当你制作网页时知道怎么去提升页面的交互性能吗?

网站的发展除了要提升目标关键词的搜索引擎排名,引来流量以外,还要增加网站的流量转化率.只有在网站的老用户不停增加的情况下,才能让网站的流量稳定下来,如果新用户跳出率等数据高,也会导致搜索引擎对你的网站评价降低,导致流量越来越少.凡科网站建设认为良好的流量增长必须配合站内的交互性提升,将新用户发展为老用户,才能让网站健康的发展,下面介绍几个制作网页时,能够提升页面交互性能的小技巧. 明显的按钮设计 不少站长在制作网页的时候为了保持网站的统一,将链接.按钮等跳转位置做得并不明显,用户其实并不喜欢这种

如何提升mysql replication的性能&&多线程传输二进制日志

如何提升replication的性能: 延迟 : 对于mysql replication来说,在没有发生故障的情况下,出现master与slave数据不同步,延迟分为以下两种情况: 经常性延迟   : 异步同步的数据差距比较大 ,周期性的,循环. 暂时性延迟   : 突发情况,导致延迟 其主要原因就是: 网络带宽 I/O 如何减少replication延迟?? 1,最好使用内网或者专线链路传输binlog数据 (千兆网卡.还不够的话,bounding 技术,扩展带宽) 在my.cnf中强制使用内

使用事务提升sqlite insert的性能

昨天发现sqlite插入性能很低,搜索了一下发现,其实sqlite的插入可以做到每秒50000条,但是处理事务的速度慢: (19) INSERT is really slow - I can only do few dozen INSERTs per second Actually, SQLite will easily do 50,000 or more INSERT statements per second on an average desktop computer. But it wi