zoukankan      html  css  js  c++  java
  • 怎样提升 RailS 应用的性能?

    提升 RAILS 应用性能的一些建议

    Is rails slow?

    「铁路非常慢」,你或许听过这个笑话,那么我们的 Rails 框架呢?
    假设说 Rails 慢,那么怎样提升 Rails APP 的性能就成了开发人员们最关注的问题。

    或许你听说过非常多提升 RoR APP 性能的方法,它们有难有易。我们须要在选择其中最能帮助开发人员脱离性能困境的。

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

    1. 数据库索引

    你的 APP 被 DB 性能限制,优秀的数据库索引能够在大型数据库表中带给你100倍的性能提升。

    然而并不是全部 Rails 开发人员都明确这一点有多重要。

    加入 indexes 非常easy:

    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秒。

    因此project师能够在全部引用參数。或者其它经常查询的參数中加入 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 应用内部完毕应用性能管理和监控,包含代码级别性能问题的可见性、性能瓶颈的高速识别与追溯、真有用户体验监控、server监控和端到端的应用性能管理。 追溯性能瓶颈至:性能表现差的 SQL 语句、第三方 API、Web Services、Caching Layers、后台任务等。

    alt text

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

    alt text

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

    alt

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

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

    7. 使用内存数据库

    当查询和排序都在内存中完毕。数据库将会执行的更快。而它们须要在磁盘上执行的时候就变得非常慢。

    解决方式:

    • 限制 DB 的大小。保证它全然适合内存。
    • 将不紧急的信息移出主要数据库。移入次要数据库或其它地方。

    • 假设有大量存储需求,考虑使用非关系型数据库。

    8. 很多其它性能建议:

    • 对静态文件使用内容分发网络,比如使用 AWS CloudFront。
    • 对须要1-2秒的载入项使用延迟载入。

    • 使用服务导向架构。使一些进程在托管栈同步进行。

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

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

    本文系 OneAPM project师编译整理。OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发人员轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。

    想阅读很多其它技术文章。请訪问 OneAPM 官方博客

  • 相关阅读:
    怎么统计指定文件夹下含有.xml格式的文件数目
    SQLServer触发器创建、删除、修改、查看
    Devexpress 学习不错的网址
    Devexpress
    SQL 查找重复项及批量修改数据成固定格式
    elementui carousel不能自适应问题
    node中console自定义样式
    forEach for for in for of性能问题
    骚东西
    关于arr.map()问题
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7083518.html
Copyright © 2011-2022 走看看