rails performance笔记
前言
之前,由于觉得网站慢。从而,搜集过来的关于Rails性能的资料,原本是ppt,翻译学习如下:
Rails 性能
Rails最坏实践
- 过早优化
- 瞎猜
- 缓存一切
- 与框架争高下
将框架已有的性能或效能利用到最大化,
常见的Rails性能问题
Rails应用的性能问题,可能存在很多中,以下是摘自别人RailsConf中演讲:
- 缓慢的Helper方法
- 复杂的路由
- 不必要的关联
- 从DB中检索太多了
- 缓慢的Session存储(内存,文件系统,数据库,各种键值对存储方式)
注:DB通常不是问题,在检索之后,解析ActiveRecord对象,耗费很大。
性能指导原则
- 算法的提升优于代码技巧
- 可维护性高于性能
- 8/2原则,只优化相关的部分
- 测量两次,削减一次
- 在灵活性和可维护性之间平衡
如何提高性能
- 寻找基准线
- 了解自己在哪
- 分析,从而发现瓶颈
- 移除瓶颈
- 重复上述过程
议程
- 分析和度量
- 编写优美高效的Ruby代码
- 使用REE 1.8.7 或 Ruby 1.9以上
- 使用更快的Ruby库
- 缓存
- SQL 和 ActiveRecord
- 考虑NoSQL存储
- 使用Rack和Rails Metal
- 对静态资源使用HTTP Server
- 前端web性能
- 使用扩展程序或内联C代码
关于Rails的性能,大体就涉及这样的一些方面。
发现问题: 分析
服务器日志分析: http://github.com/wvanbergen/request-log-analyzer,其分析的结果项如下:
- 每小时的请求分布
- 最多请求的
- HTTP方法及其返回状态
- Rails动作缓存的命中率
- 请求持续时间
- 视图渲染时间
- 数据库时间
- 阻塞进程
- 失败的进程
商业的产品: New Relic和Scout。
Rack::Bug
: 通过浏览器给出通知消息的Rails中间件
memorylogic : 内存分析, 通过在日志中添加进程id 及其相关的内存使用量,用来追踪 内存泄漏。
oink : 日志分析,从而分析出那些动作显著提升VM的堆大小
ruby-prof : 快速的Ruby代码剖析工具,其特性包含:
- 速度 - C 扩展
- Modes(模式) - 调用时间、内存使用以及对象分配
- 报告 - 生成文本和交叉引用的HTML报告
- 线程 - 支持多线程同步
- 递归调用 - 支持递归方法的调用
具体的使用,参考ruby-prof的代码地址。
Rails 命令行 : profiler命令, 貌似,Rails 3.x 不存在该命令。
性能测试 : 度量
Benchmark 标准库 : 可以使用命令benchmark(貌似,Rails 3.x 不存在该命令), 也可在程序中,使用benchmark(类名.benchmark do … end)。
rake -T
: 查看所有Rake任务,看到rake about
。没想到,js运行时居然是therubyracer
。
通用工具(黑盒测试) : httpref, ab(apache 服务器的性能工具,可以用于任意的web 服务器测试)
httpref: HP开发的web服务器,官方地址为http://www.hpl.hp.com/research/linux/httperf/。与httpref相关的工具为autobench - 包装 httpref的perl脚本,其将测试结果保存为csv格式的文件,具体的安装使用,参考http://www.oschina.net/question/12_65396 以及
http://www.oschina.net/question/12_65398
服务器能多快响应请求
- 使用web服务器响应静态文件作为基准度量
- 不要在相同的服务器中运行(I/O和CPU)
- 从尽可能近的地方运行
- 需要统计比较的有: 平均值,标准差,置信区间
高效的Ruby代码
- 实例变量快于访问器
- 操作字符串(字符串插值)快于
+
操作符 - 就地更新
- 模块和类的定义只执行一次
- 将数据缓存在实例或Class变量中
- 少用
.nil?
- 不要使用
&block
参数
Ruby中缓存:
- 变量缓存:
ActiveSupport::Memoizable
: Ruby中缓存方式 - 方法缓存: Ruby在执行method查询时,会使用缓存的方法。在运行时,避免使用如下这些会清除缓存的方法: def/undef, Module#define_
method,
alias/Module#alias_method
, Object#extend, Module#include, public/private/protected/module_function
- 常量缓存: 不要在运行时重定义常量,少定义新的常量
可维护的Rails代码
- 将代码从控制器移入模型中
- 使用RESTful
- Model/Controller/View
Ruby慢?
语言的微观性能基准 != 复杂系统中的性能
性能的其他因素:
- 应用程序架构
- 高层抽象的能力
- Rails快于很多PHP框架
使用更快的Ruby库
- XML parser : http://nokogiri.org/
- JSON parser : http://github.com/brianmario/yajl-ruby/
- CSV parser : http://www.toastyapps.com/excelsior/
- HTTP client : http://github.com/pauldix/typhoeus
- Date : http://github.com/rtomayko/date-performance
Caching
关于缓存:
- 缓存一切则过于丑陋
- 易出bug,难于测试
- 复杂: expire , security
- 限制用户接口选项
Rails中Cache的存储,存在多种选项。
view caching :
- Page Caching(caches_page/expire_page)
- Action Caching(caches_action/expire_action)
- Fragment Caching(cache do…end 以及 expire_fragment)
- 使用sweeper来提取过期的逻辑
使用memcached
- Free & open source, high-performance, distributed memory object caching system
- an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering.
- key: 256字节
- Data: 1MB
- Caching secret: key命名以及过期
SQL and ActiveRecord
ORM is a high-level library that it’s easy to forget about efficiency until it becomes a problem.
EngineYard的文章: That’s Not a Memory Leak, It’s Bloat
ORM的问题:
- N+1 查询的问题
- 添加 :include, Bullet插件
- 索引缺失, rails_indexes
- 只选择需要的, SQL查询优化, Scrooge
- 某些情况,将
:include
替换为:join
- 批量查询
- 为成组的操作设置成事务
- SQL query planner, 利用Explain关键字,query_reviewer
- 全文搜索引擎: Sphinx,Ferret
- 对领域数据采用常量
- 设置Counter cache, :counter_cache
- 使用cron和rake来存储报表
- AR缓存插件, cache-money, interlock, cache_fu 。使用这些方案时,需要额外小心
考虑NoSQL存储
- 高性能的键值存储: Redis, Tokyo Cabinet, Flare
- 大型数据的文档型存储: MongoDB, CouchDB
- Record store for high scalability and availability
存储非关键数据、点击数,下载数,在线用户记录时,不要使用RDBMS
Moneta : 键值对存储的同一界面,支持很多的键/值数据库,统一API为:
#[](key)
#[]=(key, value)
- #delete(key)
- #key?(key)
- #store(key, value, options)
- #update_key(key, options):
- #clear
Rails Metal : rack 中间件的子集,合并了routes和控制器,比controller快2到3倍,适合那些不需要ActionView的API项目。
静态文件使用web服务器或CDN
- web server比Ruby应用程序服务器快 10 倍以上
- 在启用了mod_xsendfile的Apache或者Lighttpd中,设置x_sendfile为真
web前端分析
工具: yslow, page-speed 以及 Yahoo!提出的14条性能加速建议:
- Make Fewer HTTP Requests
- Add an Expires Header
- Use a Content Delivery Network
- Gzip Components
- Put Stylesheets at the Top
- Put Scripts at the Bottom
- Avoid CSS Expressions
- Make JavaScript and CSS External
- Reduce DNS Lookups
- Minify JavaScript
- Avoid Redirects
- Remove Duplicates Scripts
- Configure ETags
- Make Ajax Cacheable ??
以及《High Performance web Sites》和《Even Faster Web Sites》。
内嵌C/C++代码
- RubyInline: Write foreign code within ruby code
- Rice: Ruby Interface for C++ Extensions
- Ruby-FFI: a ruby extension for programmatically loading dynamic libraries
参考文献
- Advanced Rails Chap.6 Performance (O’Reilly)
- Rails Rescue Handbook
- Writing Efficient Ruby Code (Addison-Wesley)
- Ruby on Rails Code Review (Peepcode)
- Rails 2 Chap. 13 Security and Performance Enhancements (friendsof)
- Deploying Rails Application Chap.9 Performance (Pragmatic)
- http://guides.rubyonrails.org/caching_with_rails.html
- http://guides.rubyonrails.org/performance_testing.html
- http://railslab.newrelic.com/scaling-rails
- http://antoniocangiano.com/2007/02/10/top-10-ruby-on-rails-performance-tips/
- http://www.engineyard.com/blog/2009/thats-not-a-memory-leak-its-bloat/
- http://jstorimer.com/ruby/2009/12/13/essential-rails-plugins-for-your-inner-dba.html
- http://asciicasts.com/episodes/161-three-profiling-tools
- http://robots.thoughtbot.com/post/163627511/a-grand-piano-for-your-violin
后记
看过了上述关于Rails性能的描述之后,挑了几个gem包进行后续深入学习和使用:
- request-log-analyzer - 日志分析的gem包
- ruby-prof - Ruby代码性能监控
- bullet - 处理SQL查询中的N+1的问题
- lol_dba - 处理模型中索引的问题
- query_reviewer - SQL查询监视,使用”EXPLAIN”命令
- moneta - 同一的键值对库的gem
改变做法了,研究gem包,直接fork过来,本地深入学习和了解。
傲娇的使用Disqus