• 怎样提升 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 官方博客

  • 相关阅读:
    atitit.ntfs ext 文件系统新特性对比
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit.跨平台预定义函数 魔术方法 魔术函数 钩子函数 api兼容性草案 v2 q216  java c# php js.docx
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7083518.html
Copyright © 2020-2023  润新知